home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / dev / lang / sofa.lha / sofa / smalleiffel / lib_se / eiffel_parser.e < prev    next >
Text File  |  2000-03-25  |  112KB  |  4,608 lines

  1. --          This file is part of SmallEiffel The GNU Eiffel Compiler.
  2. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  3. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
  4. --                       http://SmallEiffel.loria.fr
  5. -- SmallEiffel is  free  software;  you can  redistribute it and/or modify it
  6. -- under the terms of the GNU General Public License as published by the Free
  7. -- Software  Foundation;  either  version  2, or (at your option)  any  later
  8. -- version. SmallEiffel is distributed in the hope that it will be useful,but
  9. -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. -- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License
  11. -- for  more  details.  You  should  have  received a copy of the GNU General
  12. -- Public  License  along  with  SmallEiffel;  see the file COPYING.  If not,
  13. -- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14. -- Boston, MA 02111-1307, USA.
  15. --
  16. class EIFFEL_PARSER
  17.    --
  18.    -- Singleton object in charge of Eiffel parsing.
  19.    -- This singleton is shared via the GLOBALS.`eiffel_parser' once function.
  20.    --
  21.  
  22. inherit GLOBALS;
  23.  
  24. feature
  25.  
  26.    case_insensitive: BOOLEAN;
  27.      -- When flag "-case_insensitive" is on.
  28.  
  29.    no_style_warning: BOOLEAN;
  30.      -- When flag "-no_style_warning" is on.
  31.  
  32.    is_running: BOOLEAN;
  33.      -- True when the parser is running (ie. parsing of the
  34.      -- current class is not finished)..
  35.  
  36. feature {SMALL_EIFFEL}
  37.  
  38.    analyse_class(class_name: CLASS_NAME): BASE_CLASS is
  39.       require
  40.      not is_running;
  41.      not small_eiffel.is_ready;
  42.      class_name.to_string /= Void;
  43.      parser_buffer.is_ready
  44.       local
  45.      old_nbe, old_nbw: INTEGER;
  46.      path: STRING;
  47.       do
  48.      current_id := id_provider.item(class_name.to_string);
  49.      path := parser_buffer.path;
  50.      if nb_errors > 0 then
  51.         eh.append("Correct previous error(s) first.");
  52.         eh.print_as_fatal_error;
  53.      end;
  54.      debug
  55.         if small_eiffel.is_ready then
  56.            eh.append("Tried to load class ");
  57.            eh.append(path);
  58.            eh.append(" while small_eiffel `is_ready'.");
  59.            eh.print_as_warning;
  60.         end;
  61.      end;
  62.      echo.put_integer(small_eiffel.base_class_count + 1);
  63.      echo.put_character('%T');
  64.      echo.put_string(path);
  65.      echo.put_character('%N');
  66.      old_nbe := nb_errors;
  67.      old_nbw := nb_warnings;
  68.      is_running := true;
  69.      inside_function := false;
  70.      inside_once_function := false;
  71.      in_ensure := false;
  72.      last_comments := Void;
  73.      line := 1;
  74.      column := 1;
  75.      current_line := parser_buffer.item(line);
  76.      if current_line.count = 0 then
  77.         cc := '%N';
  78.      else
  79.         cc := current_line.first;
  80.      end;
  81.      !!last_base_class.make(path,class_name.to_string,current_id);
  82.      skip_comments;
  83.      a_class_declaration;
  84.      is_running := false;
  85.      parser_buffer.unset_is_ready;
  86.      Result := last_base_class;
  87.      if nb_errors - old_nbe > 0 then
  88.         show_nb_errors;
  89.         echo.w_put_string("Load class %"");
  90.         echo.w_put_string(path);
  91.         echo.w_put_string("%" aborted.%N");
  92.         Result := Void;
  93.      elseif nb_warnings - old_nbw > 0 then
  94.         show_nb_warnings;
  95.         check
  96.            Result /= Void
  97.         end;
  98.      end;
  99.      if Result /= Void then
  100.         Result.get_started;
  101.      end;
  102.       ensure
  103.      not parser_buffer.is_ready
  104.       end;
  105.  
  106. feature {COMMAND_FLAGS}
  107.  
  108.    set_case_insensitive is
  109.       do
  110.      case_insensitive := true;
  111.       end;
  112.  
  113.    set_no_style_warning is
  114.       do
  115.      no_style_warning := true;
  116.       end;
  117.  
  118. feature {CECIL_POOL}
  119.  
  120.    connect_to_cecil: STRING is
  121.      -- Return the cecil file path (first line).
  122.       require
  123.      not is_running;
  124.      nb_errors = 0;
  125.      run_control.cecil_path /= Void
  126.       local
  127.      path: STRING;
  128.       do
  129.      path := run_control.cecil_path;
  130.      echo.put_string("Parsing Cecil File : ");
  131.      echo.put_string(path);
  132.      echo.put_character('%N');
  133.      parser_buffer.load_file(path);
  134.      if not parser_buffer.is_ready then
  135.         fatal_error(
  136.         "Cannot open Cecil file (use -verbose flag for details).");
  137.      end;
  138.      path := parser_buffer.path;
  139.      current_id := id_provider.item(path);
  140.      is_running := true;
  141.      formal_generic_list := Void;
  142.      inside_function := false;
  143.      inside_once_function := false;
  144.      in_ensure := false;
  145.      last_comments := Void;
  146.      line := 1;
  147.      column := 1;
  148.      current_line := parser_buffer.item(line);
  149.      last_base_class := Void;
  150.      if current_line.count = 0 then
  151.         cc := '%N';
  152.      else
  153.         cc := current_line.first;
  154.      end;
  155.      skip_comments;
  156.      from
  157.         !!Result.make(32);
  158.      until
  159.         cc = '%N' or else cc = end_of_text
  160.      loop
  161.         Result.extend(cc);
  162.         next_char;
  163.      end;
  164.      skip_comments;
  165.      if cc = end_of_text then
  166.         fatal_error("Empty Cecil file (use -verbose flag for details).");
  167.      end;
  168.       end;
  169.  
  170.    end_of_input: BOOLEAN is
  171.       do
  172.      Result := cc = end_of_text;
  173.       end;
  174.  
  175.    parse_c_name: STRING is
  176.       do
  177.      from
  178.         !!Result.make(32);
  179.      until
  180.         cc.is_separator
  181.      loop
  182.         Result.extend(cc);
  183.         next_char;
  184.      end;
  185.      skip_comments;
  186.       end;
  187.  
  188.    parse_run_type: TYPE is
  189.       do
  190.      if a_class_type then
  191.         Result := last_class_type;
  192.      else
  193.         fcp(em16);
  194.      end;
  195.       ensure
  196.      nb_errors = 0
  197.       end;
  198.  
  199.    parse_feature_name: FEATURE_NAME is
  200.       do
  201.      if a_feature_name then
  202.         Result := last_feature_name;
  203.      else
  204.         fcp(em2);
  205.      end;
  206.       ensure
  207.      nb_errors = 0
  208.       end;
  209.  
  210.    disconnect is
  211.       do
  212.      is_running := false;
  213.      parser_buffer.unset_is_ready;
  214.       end;
  215.  
  216. feature {C_PRETTY_PRINTER}
  217.  
  218.    show_nb_warnings is
  219.       local
  220.      do_it: BOOLEAN;
  221.       do
  222.      if echo.verbose then
  223.         do_it := true;
  224.      elseif eh.no_warning then
  225.      else
  226.         do_it := true;
  227.      end;
  228.      if do_it then
  229.         show_nb(nb_warnings," warning(s).%N");
  230.      end;
  231.       end;
  232.  
  233.    show_nb_errors is
  234.       do
  235.      show_nb(nb_errors," error(s).%N");
  236.       end;
  237.  
  238. feature {COMPILE_TO_C,COMPILE_TO_JVM}
  239.  
  240.    set_drop_comments is
  241.       do
  242.      drop_comments := true;
  243.       end;
  244.  
  245. feature {TMP_FEATURE}
  246.  
  247.    ecp(msg: STRING) is
  248.      -- Error at current position.
  249.       do
  250.      error(current_position,msg);
  251.       end;
  252.  
  253. feature {NONE}
  254.  
  255.    end_of_text: CHARACTER is '%/0/'; -- Flag of the end of the `text'.
  256.  
  257.    last_comments: COMMENT;
  258.      -- Void or waiting comment.
  259.  
  260.    inside_function: BOOLEAN;
  261.      -- True when a function (once or non-once) is parsed.
  262.  
  263.    inside_once_function: BOOLEAN;
  264.      -- True when a once function is parsed.
  265.  
  266.    formal_generic_list: FORMAL_GENERIC_LIST;
  267.      -- Void or not empty list of formal generic arguments.
  268.  
  269.    in_ensure: BOOLEAN;
  270.      -- True during the parsing of a ensure clause.
  271.  
  272.    in_rescue: BOOLEAN;
  273.      -- True during the parsing of a rescue clause.
  274.  
  275.    arguments: FORMAL_ARG_LIST;
  276.      -- Void or actual formal arguments list.
  277.  
  278.    local_vars: LOCAL_VAR_LIST;
  279.      -- Void or actual local variables list.
  280.  
  281.    ok: BOOLEAN;
  282.      -- Dummy variable to call functions.
  283.  
  284.    tmp_name: TMP_NAME;
  285.  
  286.    last_ascii_code: INTEGER;
  287.    last_base_class: BASE_CLASS;
  288.    last_base_type: TYPE;
  289.    last_binary: INFIX_NAME;
  290.    last_bit_constant: BIT_CONSTANT;
  291.    last_boolean_constant: BOOLEAN_CONSTANT;
  292.    last_character_or_integer: BASE_TYPE_CONSTANT;
  293.    last_character_constant: CHARACTER_CONSTANT;
  294.    last_class_name: CLASS_NAME;
  295.    last_class_type: TYPE;
  296.    last_expression: EXPRESSION;
  297.    last_feature_declaration: E_FEATURE;
  298.    last_feature_name: FEATURE_NAME;
  299.    last_feature_name_list: FEATURE_NAME_LIST;
  300.    last_keyword: STRING; -- Should be removed.
  301.    last_type_formal_generic: TYPE_FORMAL_GENERIC;
  302.    last_infix: INFIX_NAME;
  303.    last_prefix: PREFIX_NAME;
  304.    last_integer_constant: INTEGER_CONSTANT;
  305.    last_instruction: INSTRUCTION;
  306.    last_index_value: EXPRESSION;
  307.    last_manifest_constant: EXPRESSION;
  308.    last_manifest_string: MANIFEST_STRING;
  309.    last_parent: PARENT;
  310.    last_real_constant: REAL_CONSTANT;
  311.    last_type: TYPE;
  312.    last_tag_mark: TAG_NAME;
  313.  
  314.    a_argument: BOOLEAN is
  315.       local
  316.      rank: INTEGER;
  317.       do
  318.      if arguments /= Void then
  319.         rank := arguments.rank_of(tmp_name.aliased_string);
  320.         if rank > 0 then
  321.            last_expression := tmp_name.to_argument_name2(arguments,rank);
  322.            Result := true;
  323.         end;
  324.      end;
  325.       end;
  326.  
  327.    a_current: BOOLEAN is
  328.       do
  329.      if tmp_name.is_current then
  330.         !WRITTEN_CURRENT!last_expression.make(tmp_name.start_position);
  331.         Result := true;
  332.      end;
  333.       end;
  334.  
  335.    a_formal_arg_list is
  336.      --++ formal_arg_list -> ["(" {declaration_group ";" ...} ")"]
  337.      --++ declaration_group -> {identifier "," ...}+ ":" type
  338.       local
  339.      name: ARGUMENT_NAME1;
  340.      name_list: ARRAY[ARGUMENT_NAME1];
  341.      declaration: DECLARATION;
  342.      list: ARRAY[DECLARATION];
  343.      state: INTEGER;
  344.      -- state 0 : waiting for the first name of a group.
  345.      -- state 1 : waiting "," or ":".
  346.      -- state 2 : waiting for a name (not the first).
  347.      -- state 3 : waiting for type mark.
  348.      -- state 4 : waiting ";" or ")".
  349.      -- state 5 : end.
  350.      -- state 6 : error.
  351.       do
  352.      arguments := Void;
  353.      if skip1('(') then
  354.         from
  355.         until
  356.            state > 4
  357.         loop
  358.            inspect
  359.           state
  360.            when 0 then
  361.           if a_identifier then
  362.              name := tmp_name.to_argument_name1;
  363.              state := 1;
  364.           elseif skip1(')') then
  365.              state := 5;
  366.           else
  367.              state := 6;
  368.           end;
  369.            when 1 then
  370.           if skip1(':') then
  371.              if name_list /= Void then
  372.             name_list.add_last(name);
  373.             name := Void;
  374.              end;
  375.              state := 3;
  376.           else
  377.              ok := skip1(',');
  378.              if name_list = Void then
  379.             !!name_list.with_capacity(2,1);
  380.              end;
  381.              name_list.add_last(name);
  382.              name := Void;
  383.              state := 2;
  384.           end;
  385.            when 2 then
  386.           if a_identifier then
  387.              name := tmp_name.to_argument_name1;
  388.              state := 1;
  389.           elseif cc = ',' or else cc = ';' then
  390.              wcp(em13);
  391.              ok := skip1(',') or else skip1(';');
  392.           else
  393.              state := 6;
  394.           end;
  395.            when 3 then
  396.           if a_type then
  397.              if name_list /= Void then
  398.             !DECLARATION_GROUP!declaration.make(name_list,
  399.                                                 last_type);
  400.             name_list := Void;
  401.              else
  402.             !DECLARATION_1!declaration.make(name,last_type);
  403.             name := Void;
  404.              end;
  405.              if list = Void then
  406.             !!list.with_capacity(2,1);
  407.              end;
  408.              list.add_last(declaration);
  409.              declaration := Void;
  410.              state := 4;
  411.           else
  412.              state := 6;
  413.           end;
  414.            else -- state = 4
  415.           if skip1(')') then
  416.              state := 5;
  417.           elseif cc = ',' then
  418.              wcp("Substitute with %";%".");
  419.              ok := skip1(',');
  420.              state := 0;
  421.           else
  422.              ok := skip1(';');
  423.              state := 0;
  424.           end;
  425.            end;
  426.         end;
  427.         if state = 6 then
  428.            fcp("Bad formal arguments list.");
  429.         elseif list = Void then
  430.            wcp("Empty formal argument list (deleted).");
  431.         else
  432.            !!arguments.make(list);
  433.            tmp_feature.set_arguments(arguments);
  434.         end;
  435.      end;
  436.       end;
  437.  
  438.    a_local_var_list is
  439.      --++ local_var_list -> [{declaration_group ";" ...}]
  440.      --++ declaration_group -> {identifier "," ...}+ ":" type
  441.       local
  442.      name: LOCAL_NAME1;
  443.      name_list: ARRAY[LOCAL_NAME1];
  444.      declaration: DECLARATION;
  445.      list: ARRAY[DECLARATION];
  446.      rank, state: INTEGER;
  447.      -- state 0 : waiting for the first name of a group.
  448.      -- state 1 : waiting "," or ":".
  449.      -- state 2 : waiting for a name (not the first).
  450.      -- state 3 : waiting for type mark.
  451.      -- state 4 : waiting ";".
  452.      -- state 5 : end.
  453.      -- state 6 : error.
  454.       do
  455.      from
  456.      until
  457.         state > 4
  458.      loop
  459.         inspect
  460.            state
  461.         when 0 then
  462.            if a_identifier then
  463.           name := tmp_name.to_local_name1;
  464.           state := 1;
  465.           if arguments /= Void then
  466.              rank := arguments.rank_of(name.to_string);
  467.              if rank > 0 then
  468.             eh.add_position(name.start_position);
  469.             error(arguments.name(rank).start_position,
  470.                   "Same identifier appears twice (local/formal).");
  471.              end;
  472.           end;
  473.            elseif cc = ',' or else cc = ';' then
  474.           wcp(em13);
  475.           ok := skip1(',') or else skip1(';');
  476.            else
  477.           state := 5;
  478.            end;
  479.         when 1 then
  480.            if skip1(':') then
  481.           if name_list /= Void then
  482.              name_list.add_last(name);
  483.              name := Void;
  484.           end;
  485.           state := 3;
  486.            else
  487.           if cc = ';' then
  488.              wcp("Substitute with %",%".");
  489.              ok := skip1(';');
  490.           else
  491.              ok := skip1(',');
  492.           end;
  493.           if name_list = Void then
  494.              !!name_list.with_capacity(2,1);
  495.           end;
  496.           name_list.add_last(name);
  497.           name := Void;
  498.           state := 2;
  499.            end;
  500.         when 2 then
  501.            if a_identifier then
  502.           name := tmp_name.to_local_name1;
  503.           state := 1;
  504.           if arguments /= Void then
  505.              rank := arguments.rank_of(name.to_string);
  506.              if rank > 0 then
  507.             eh.add_position(name.start_position);
  508.             eh.add_position(arguments.name(rank).start_position);
  509.             eh.append("Same identifier appears twice (local/formal).");
  510.             eh.print_as_error;
  511.              end;
  512.           end;
  513.            elseif cc = ',' or else cc = ';' then
  514.           wcp(em13);
  515.           ok := skip1(',') or else skip1(';');
  516.            else
  517.           state := 6;
  518.            end;
  519.         when 3 then
  520.            if a_type then
  521.           if name_list /= Void then
  522.              !DECLARATION_GROUP!declaration.make(name_list,last_type);
  523.              name_list := Void;
  524.           else
  525.              !DECLARATION_1!declaration.make(name,last_type);
  526.              name := Void;
  527.           end;
  528.           if list = Void then
  529.              !!list.with_capacity(2,1);
  530.           end;
  531.           list.add_last(declaration);
  532.           state := 4;
  533.            else
  534.           state := 6;
  535.            end;
  536.         else -- state = 4
  537.            if cc = ',' then
  538.           wcp("Substitute with %";%".");
  539.           ok := skip1(',');
  540.           state := 0;
  541.            else
  542.           ok := skip1(';');
  543.           state := 0;
  544.            end;
  545.         end;
  546.      end;
  547.      if state = 6 then
  548.         fcp("Bad local variable list.");
  549.      elseif list /= Void then
  550.         !!local_vars.make(list);
  551.         tmp_feature.set_local_vars(local_vars);
  552.      end;
  553.       end;
  554.  
  555.    a_local_variable: BOOLEAN is
  556.       local
  557.      rank: INTEGER;
  558.       do
  559.      if local_vars /= Void then
  560.         rank := local_vars.rank_of(tmp_name.aliased_string);
  561.         if rank > 0 then
  562.            last_expression := tmp_name.to_local_name2(local_vars,rank);
  563.            Result := true;
  564.         end;
  565.      end;
  566.       end;
  567.  
  568.    a_result: BOOLEAN is
  569.       do
  570.      if tmp_name.is_result then
  571.         last_expression := last_result;
  572.         Result := true;
  573.      end;
  574.       end;
  575.  
  576.    a_void: BOOLEAN is
  577.       do
  578.      if tmp_name.is_void then
  579.         last_expression := tmp_name.to_e_void;
  580.         Result := true;
  581.      end;
  582.       end;
  583.  
  584.    get_comments: COMMENT is
  585.       do
  586.      Result := last_comments;
  587.      last_comments := Void;
  588.       end;
  589.  
  590.    start_line, start_column: INTEGER;
  591.      -- To store beginning position of : `a_keyword', `a_integer',
  592.      -- `a_real', `skip1', `skip2' and `skip1unless2'.
  593.  
  594.    a_keyword(keyword: STRING): BOOLEAN is
  595.      -- Look for `keyword' beginning strictly at current position.
  596.      -- A keyword is never followed by a character of
  597.      -- this set : 'A'..'Z','a'..'z','0'..'9','_'.
  598.      -- When Result is true, `last_keyword' is updated.
  599.       require
  600.      keyword.count >= 1
  601.       local
  602.      c, i: INTEGER;
  603.      back_cc: CHARACTER;
  604.       do
  605.      from
  606.         back_cc := cc;
  607.         start_line := line;
  608.         start_column := column;
  609.         c := keyword.count;
  610.         i := 1;
  611.      until
  612.         c <= 0
  613.      loop
  614.         if cc.same_as(keyword.item(i)) then
  615.            i := i + 1;
  616.            c := c - 1;
  617.            next_char;
  618.         else
  619.            c := -1;
  620.         end;
  621.      end;
  622.      if c = 0 then
  623.         inspect
  624.            cc
  625.         when ' ','%N','%T','-' then
  626.            Result := true;
  627.            last_keyword := keyword;
  628.            skip_comments;
  629.         when 'a'..'z','A'..'Z','0'..'9','_' then
  630.            column := start_column;
  631.            cc := back_cc;
  632.         else
  633.            Result := true;
  634.            last_keyword := keyword;
  635.         end;
  636.      else
  637.         column := start_column;
  638.         cc := back_cc;
  639.      end;
  640.       end;
  641.  
  642.    a_ascii_code is
  643.      -- To read a character given as an ascii code in a manifest
  644.      -- constant CHARACTER or STRING;
  645.      -- Require/Ensure : cc = '/'.
  646.       local
  647.      counter: INTEGER;
  648.       do
  649.      from
  650.         check
  651.            cc = '/'
  652.         end;
  653.         next_char;
  654.         counter := 0;
  655.         last_ascii_code := 0;
  656.      until
  657.         counter > 3 or else cc = '/'
  658.      loop
  659.         inspect
  660.            cc
  661.         when '0' .. '9' then
  662.            last_ascii_code := last_ascii_code * 10 + cc.value;
  663.         else
  664.            fcp("Unexpected character in ascii code.");
  665.         end;
  666.         counter := counter + 1;
  667.         next_char;
  668.      end;
  669.      if counter = 0 then
  670.         fcp("Bad (empty ?) ascii code.");
  671.      elseif counter > 3 then
  672.         fcp("Three digit is enought for an ascii code.");
  673.      else
  674.         check
  675.            cc = '/'
  676.         end;
  677.      end;
  678.       end;
  679.  
  680.    go_back_at(l, c: INTEGER) is
  681.      -- Go back to some existing `l',`c'.
  682.       require
  683.      l >= 1;
  684.      c >= 1
  685.       do
  686.      line := l;
  687.      column := c;
  688.      current_line := parser_buffer.item(l);
  689.      cc := current_line.item(c);
  690.       end;
  691.  
  692.    next_char is
  693.       do
  694.      if column < current_line.count then
  695.         column := column + 1;
  696.         cc := current_line.item(column);
  697.      elseif column = current_line.count then
  698.         column := column + 1;
  699.         cc := '%N';
  700.      elseif line = parser_buffer.count then
  701.         cc := end_of_text;
  702.      else
  703.         line := line + 1;
  704.         column := 1;
  705.         current_line := parser_buffer.item(line);
  706.         if current_line.count = 0 then
  707.            cc := '%N';
  708.         else
  709.            cc := current_line.first;
  710.         end;
  711.      end;
  712.       end;
  713.  
  714.    skip1(char: CHARACTER): BOOLEAN is
  715.       do
  716.      if char = cc then
  717.         start_line := line;
  718.         start_column := column;
  719.         Result := true;
  720.         next_char;
  721.         skip_comments;
  722.      end;
  723.       end;
  724.  
  725.    skip2(c1, c2: CHARACTER): BOOLEAN is
  726.       do
  727.      if c1 = cc then
  728.         start_line := line;
  729.         start_column := column;
  730.         next_char;
  731.         if c2 = cc then
  732.            Result := true;
  733.            next_char;
  734.            skip_comments;
  735.         else
  736.            cc := c1;
  737.            column := start_column;
  738.         end;
  739.      end;
  740.       end;
  741.  
  742.    skip1unless2(c1, c2: CHARACTER): BOOLEAN is
  743.       do
  744.      start_line := line;
  745.      start_column := column;
  746.      if cc = c1 then
  747.         next_char;
  748.         if cc = c2 then
  749.            cc := c1;
  750.            column := start_column;
  751.         else
  752.            Result := true;
  753.            skip_comments;
  754.         end;
  755.      end;
  756.       end;
  757.  
  758.    skip_comments is
  759.      -- Skip separators and comments if any.
  760.      -- Unless `drop_comments', comments are stored in `last_comments'.
  761.       local
  762.      sp: POSITION;
  763.      stop: BOOLEAN;
  764.       do
  765.      from
  766.      until
  767.         stop
  768.      loop
  769.         inspect
  770.            cc
  771.         when ' ','%T','%N' then
  772.            next_char;
  773.         when '-' then
  774.            next_char;
  775.            if cc = '-' then
  776.           if drop_comments then
  777.              if line = parser_buffer.count then
  778.             cc := end_of_text;
  779.             stop := true;
  780.              else
  781.             line := line + 1;
  782.             column := 1;
  783.             current_line := parser_buffer.item(line);
  784.             if current_line.count = 0 then
  785.                cc := '%N';
  786.             else
  787.                cc := current_line.first;
  788.             end;
  789.              end;
  790.           else
  791.              from
  792.             sp := pos(line,column - 1);
  793.             next_char;
  794.             lcs.clear;
  795.              until
  796.             cc = '%N'
  797.              loop
  798.             lcs.extend(cc);
  799.             next_char;
  800.              end;
  801.              if last_comments = Void then
  802.             !!last_comments.make(sp,lcs.twin);
  803.              else
  804.             last_comments.add_last(lcs.twin);
  805.              end;
  806.           end;
  807.            else
  808.           cc := '-';
  809.           column := column - 1;
  810.           stop := true;
  811.            end;
  812.         else
  813.            stop := true;
  814.         end;
  815.      end;
  816.       end;
  817.  
  818.    a_bit_constant: BOOLEAN is
  819.       local
  820.      l, c, state: INTEGER;
  821.      -- state 0 : first bit read.
  822.      -- state 1 : happy end.
  823.      -- state 2 : error end.
  824.       do
  825.      if cc = '0' or else cc = '1' then
  826.         from
  827.            l := line;
  828.            c := column;
  829.            tmp_string.clear;
  830.            tmp_string.extend(cc);
  831.         until
  832.            state > 0
  833.         loop
  834.            next_char;
  835.            inspect
  836.           cc
  837.            when '0','1' then
  838.           tmp_string.extend(cc);
  839.            when 'b','B' then
  840.           !!last_bit_constant.make(pos(l,c),tmp_string.twin);
  841.           next_char;
  842.           skip_comments;
  843.           state := 1;
  844.           Result := true;
  845.            else
  846.           go_back_at(l,c);
  847.           state := 2;
  848.            end;
  849.         end;
  850.      end;
  851.       end;
  852.  
  853.    a_character_constant: BOOLEAN is
  854.       local
  855.      sp: POSITION;
  856.      state, printing_mode: INTEGER;
  857.      value: CHARACTER;
  858.      -- state 0 : first '%'' read.
  859.      -- state 1 : first '%%' read.
  860.      -- state 2 : wait for second '%''.
  861.      -- state 3 : happy end.
  862.       do
  863.      if cc = '%'' then
  864.         from
  865.            sp := pos(line,column);
  866.            Result := true;
  867.         until
  868.            state > 2
  869.         loop
  870.            next_char;
  871.            inspect
  872.           state
  873.            when 0 then
  874.           inspect
  875.              cc
  876.           when '%%' then
  877.              state := 1;
  878.           when '%'' then
  879.              fcp(em10);
  880.              state := 2;
  881.           else
  882.              value := cc;
  883.              printing_mode := 0;
  884.              state := 2;
  885.           end;
  886.            when 1 then
  887.           printing_mode := 1;
  888.           state := 2;
  889.           inspect
  890.              cc
  891.           when 'A' then
  892.              value := '%A';
  893.           when 'B' then
  894.              value := '%B';
  895.           when 'C' then
  896.              value := '%C';
  897.           when 'D' then
  898.              value := '%D';
  899.           when 'F' then
  900.              value := '%F';
  901.           when 'H' then
  902.              value := '%H';
  903.           when 'L' then
  904.              value := '%L';
  905.           when 'N' then
  906.              value := '%N';
  907.           when 'Q' then
  908.              value := '%Q';
  909.           when 'R' then
  910.              value := '%R';
  911.           when 'S' then
  912.              value := '%S';
  913.           when 'T' then
  914.              value := '%T';
  915.           when 'U' then
  916.              value := '%U';
  917.           when 'V' then
  918.              value := '%V';
  919.           when '%%' then
  920.              value := '%%';
  921.           when '%'' then
  922.              value := '%'';
  923.           when '%"' then
  924.              value := '%"';
  925.           when '(' then
  926.              value := '%(';
  927.           when ')' then
  928.              value := '%)';
  929.           when '<' then
  930.              value := '%<';
  931.           when '>' then
  932.              value := '%>';
  933.           when '/' then
  934.              a_ascii_code;
  935.              value := last_ascii_code.to_character;
  936.              printing_mode := 2;
  937.           else
  938.              fcp("Unknown special character.");
  939.           end;
  940.            else -- state = 2
  941.           state := 3;
  942.           inspect
  943.              cc
  944.           when '%'' then
  945.           else
  946.              fcp(em10);
  947.           end;
  948.           next_char;
  949.           skip_comments;
  950.            end;
  951.         end;
  952.         !!last_character_constant.make(sp,value,printing_mode);
  953.      end;
  954.       end;
  955.  
  956.    a_constant: BOOLEAN is
  957.      -- Only true for constant allowed in "when of inspect".
  958.       local
  959.      implicit_current: IMPLICIT_CURRENT;
  960.      sfn: SIMPLE_FEATURE_NAME;
  961.       do
  962.      if a_identifier then
  963.         Result := true;
  964.         sfn := tmp_name.to_simple_feature_name;
  965.         !!implicit_current.make(sfn.start_position);
  966.         !CALL_0_C!last_expression.make(implicit_current,sfn);
  967.      elseif a_character_constant then
  968.         Result := true;
  969.         last_expression := last_character_constant;
  970.      elseif a_integer_constant then
  971.         Result := true;
  972.         last_expression := last_integer_constant;
  973.      end;
  974.       end;
  975.  
  976.    a_base_class_name: BOOLEAN is
  977.       local
  978.      state, c: INTEGER;
  979.      do_warning: BOOLEAN;
  980.      -- state 0 : first letter read.
  981.      -- state 1 : end.
  982.       do
  983.      if cc.is_letter then
  984.         from
  985.            if cc >= 'a' then
  986.           do_warning := true;
  987.           cc := cc.to_upper;
  988.            end;
  989.            c := column;
  990.            tmp_name.reset(pos(line,c));
  991.            tmp_name.extend(cc);
  992.         until
  993.            state > 0
  994.         loop
  995.            next_char;
  996.            inspect
  997.           cc
  998.            when 'A'..'Z','0'..'9','_' then
  999.           tmp_name.extend(cc);
  1000.            when 'a'..'z' then
  1001.           do_warning := true;
  1002.           tmp_name.extend(cc.to_upper);
  1003.            else
  1004.           state := 1;
  1005.            end;
  1006.         end;
  1007.         if tmp_name.isa_keyword then
  1008.            cc := tmp_name.buffer.first;
  1009.            column := c;
  1010.         else
  1011.            Result := true;
  1012.            skip_comments;
  1013.            if do_warning then
  1014.           warning(tmp_name.start_position,em14);
  1015.            end;
  1016.            last_class_name := tmp_name.to_class_name;
  1017.         end;
  1018.      end;
  1019.       end;
  1020.  
  1021.    a_base_class_name1 is
  1022.      -- Read the current base class name.
  1023.       local
  1024.      cn: CLASS_NAME;
  1025.      bc: BASE_CLASS;
  1026.       do
  1027.      bc := last_base_class;
  1028.      cn := bc.name;
  1029.      cn.set_accurate_position(pos(line,column));
  1030.      if a_base_class_name then
  1031.         if last_class_name.to_string /= cn.to_string then
  1032.            eh.add_position(last_class_name.start_position);
  1033.            eh.append(fz_01);
  1034.            eh.append(bc.path);
  1035.            eh.append("%" does not contains class %"");
  1036.            eh.append(cn.to_string);
  1037.            fatal_error(fz_03);
  1038.         end;
  1039.      else
  1040.         fcp(em15);
  1041.      end;
  1042.      if forbidden_class.fast_has(cn.to_string) then
  1043.         eh.add_position(cn.start_position);
  1044.         fatal_error("Cannot write such a class.");
  1045.      end;
  1046.       end;
  1047.    
  1048.    a_type_formal_generic: BOOLEAN is
  1049.       local
  1050.      fga: FORMAL_GENERIC_ARG;
  1051.      cn: CLASS_NAME;
  1052.      rank: INTEGER;
  1053.       do
  1054.      if formal_generic_list /= Void then
  1055.         from
  1056.            rank := 1;
  1057.         until
  1058.            Result or else rank > formal_generic_list.count
  1059.         loop
  1060.            fga := formal_generic_list.item(rank);
  1061.            if a_keyword(fga.name.to_string) then
  1062.           !!cn.make(fga.name.to_string,pos(start_line,start_column));
  1063.           !!last_type_formal_generic.make(cn,rank);
  1064.           Result := true;
  1065.            end;
  1066.            rank := rank + 1;
  1067.         end;
  1068.      end;
  1069.       end;
  1070.  
  1071.    a_free_operator: BOOLEAN is
  1072.      --++ free_operator -> "@..." |
  1073.      --++                  "#..." |
  1074.      --++                  "|..." |
  1075.      --++                  "&..."
  1076.      --++
  1077.       do
  1078.      if (cc = '@') or else
  1079.         (cc = '#') or else
  1080.         (cc = '|') or else
  1081.         (cc = '&') then
  1082.         Result := true;
  1083.         from
  1084.            tmp_name.reset(pos(line,column));
  1085.            tmp_name.extend(cc);
  1086.            next_char;
  1087.         until
  1088.            (cc = '%N') or else
  1089.            (cc = ' ') or else
  1090.            (cc = '%T') or else
  1091.            (cc = '%"')
  1092.         loop
  1093.            tmp_name.extend(cc);
  1094.            next_char;
  1095.         end;
  1096.         skip_comments;
  1097.      end;
  1098.       end;
  1099.  
  1100.    a_identifier: BOOLEAN is
  1101.       do
  1102.      if case_insensitive then
  1103.         Result := a_identifier1;
  1104.      else
  1105.         Result := a_identifier2;
  1106.      end;
  1107.       end;
  1108.  
  1109.    a_integer: BOOLEAN is
  1110.       local
  1111.      sp: POSITION;
  1112.      state, value: INTEGER;
  1113.      -- state 0 : 1st digit read (no '_' encountered).
  1114.      -- state 1 : 2nd digit read (no '_' encountered).
  1115.      -- state 2 : 3rd digit read (no '_' encountered).
  1116.      -- state 3 : more than 3 digit read (no '_' encountered).
  1117.      -- state 4 : after '_'.
  1118.      -- state 5 : after '_' and 1 digit read.
  1119.      -- state 6 : after '_' and 2 digit read.
  1120.      -- state 7 : after '_' and 3 digit read.
  1121.      -- state 8 : satisfaction state.
  1122.       do
  1123.      if cc.is_digit then
  1124.         from
  1125.            Result := true;
  1126.            sp := pos(line,column);
  1127.            value := cc.value;
  1128.         until
  1129.            state > 7
  1130.         loop
  1131.            next_char;
  1132.            inspect
  1133.           state
  1134.            when 0 then
  1135.           inspect
  1136.              cc
  1137.           when '0'..'9' then
  1138.              value := value * 10 + cc.value;
  1139.              state := 1;
  1140.           when '_' then
  1141.              state := 4;
  1142.           else
  1143.              state := 8;
  1144.           end;
  1145.            when 1 then
  1146.           inspect
  1147.              cc
  1148.           when '0'..'9' then
  1149.              value := value * 10 + cc.value;
  1150.              state := 2;
  1151.           when '_' then
  1152.              state := 4;
  1153.           else
  1154.              state := 8;
  1155.           end;
  1156.            when 2 then
  1157.           inspect
  1158.              cc
  1159.           when '0'..'9' then
  1160.              value := value * 10 + cc.value;
  1161.              state := 3;
  1162.           when '_' then
  1163.              state := 4;
  1164.           else
  1165.              state := 8;
  1166.           end;
  1167.            when 3 then
  1168.           inspect
  1169.              cc
  1170.           when '0'..'9' then
  1171.              value := value * 10 + cc.value;
  1172.           when '_' then
  1173.              fcp(em9);
  1174.           else
  1175.              state := 8;
  1176.           end;
  1177.            when 4 then
  1178.           inspect
  1179.              cc
  1180.           when '0'..'9' then
  1181.              value := value * 10 + cc.value;
  1182.              state := 5;
  1183.           else
  1184.              fcp(em9);
  1185.           end;
  1186.            when 5 then
  1187.           inspect
  1188.              cc
  1189.           when '0'..'9' then
  1190.              value := value * 10 + cc.value;
  1191.              state := 6;
  1192.           else
  1193.              fcp(em9);
  1194.           end;
  1195.            when 6 then
  1196.           inspect
  1197.              cc
  1198.           when '0'..'9' then
  1199.              value := value * 10 + cc.value;
  1200.              state := 7;
  1201.           else
  1202.              fcp(em9);
  1203.           end;
  1204.            when 7 then
  1205.           inspect
  1206.              cc
  1207.           when '0'..'9' then
  1208.              fcp(em9);
  1209.           when '_' then
  1210.              state := 4;
  1211.           else
  1212.              state := 8;
  1213.           end;
  1214.            end;
  1215.         end;
  1216.         if cc.is_letter then
  1217.            fcp(em17);
  1218.         end;
  1219.         skip_comments;
  1220.         !!last_integer_constant.make(value,sp);
  1221.      end;
  1222.       end;
  1223.  
  1224.    a_manifest_string: BOOLEAN is
  1225.       local
  1226.      state: INTEGER;
  1227.      -- state 0 : inside string.
  1228.      -- state 1 : just read a '%%'.
  1229.      -- state 2 : extended form starting (waiting for '%N').
  1230.      -- state 3 : extended form ending (waiting for '%%').
  1231.      -- state 4 : happy end.
  1232.       do
  1233.      if cc = '%"' then
  1234.         from
  1235.            Result := true;
  1236.            !!last_manifest_string.make(pos(line,column));
  1237.         until
  1238.            state > 3
  1239.         loop
  1240.            next_char;
  1241.            inspect
  1242.           state
  1243.            when 0 then
  1244.           inspect
  1245.              cc
  1246.           when '%N' then
  1247.              fcp(em8);
  1248.           when '%"' then
  1249.              state := 4;
  1250.           when '%%' then
  1251.              state := 1;
  1252.           else
  1253.              last_manifest_string.add(cc);
  1254.           end;
  1255.            when 1 then
  1256.           state := 0;
  1257.           inspect
  1258.              cc
  1259.           when '%N' then
  1260.              state := 3;
  1261.           when 'A' then
  1262.              last_manifest_string.add_percent('%A');
  1263.           when 'B' then
  1264.              last_manifest_string.add_percent('%B');
  1265.           when 'C' then
  1266.              last_manifest_string.add_percent('%C');
  1267.           when 'D' then
  1268.              last_manifest_string.add_percent('%D');
  1269.           when 'F' then
  1270.              last_manifest_string.add_percent('%F');
  1271.           when 'H' then
  1272.              last_manifest_string.add_percent('%H');
  1273.           when 'L' then
  1274.              last_manifest_string.add_percent('%L');
  1275.           when 'N' then
  1276.              last_manifest_string.add_percent('%N');
  1277.           when 'Q' then
  1278.              last_manifest_string.add_percent('%Q');
  1279.           when 'R' then
  1280.              last_manifest_string.add_percent('%R');
  1281.           when 'S' then
  1282.              last_manifest_string.add_percent('%S');
  1283.           when 'T' then
  1284.              last_manifest_string.add_percent('%T');
  1285.           when 'U' then
  1286.              last_manifest_string.add_percent('%U');
  1287.           when 'V' then
  1288.              last_manifest_string.add_percent('%V');
  1289.           when '%%' then
  1290.              last_manifest_string.add_percent('%%');
  1291.           when '%'' then
  1292.              last_manifest_string.add_percent('%'');
  1293.           when '%"' then
  1294.              last_manifest_string.add_percent('%"');
  1295.           when '(' then
  1296.              last_manifest_string.add_percent('%(');
  1297.           when ')' then
  1298.              last_manifest_string.add_percent('%)');
  1299.           when '<' then
  1300.              last_manifest_string.add_percent('%<');
  1301.           when '>' then
  1302.              last_manifest_string.add_percent('%>');
  1303.           when '/' then
  1304.              a_ascii_code;
  1305.              last_manifest_string.add_ascii(last_ascii_code.to_character);
  1306.           when ' ','%T' then
  1307.              state := 2;
  1308.           else
  1309.              fcp("Unknown special character.");
  1310.              state := 0;
  1311.           end;
  1312.            when 2 then
  1313.           inspect
  1314.              cc
  1315.           when '%N' then
  1316.              state := 3;
  1317.           when ' ','%T' then
  1318.           else
  1319.              fcp("In extended form of manifest string.%
  1320.              %Bad character after '%%'.");
  1321.           end;
  1322.            else -- state = 3
  1323.           inspect
  1324.              cc
  1325.           when ' ','%T' then
  1326.           when '%%' then
  1327.              last_manifest_string.break_line;
  1328.              state := 0;
  1329.           when '%N' then
  1330.              fcp(em8);
  1331.              state := 0;
  1332.           else
  1333.              fcp("In extended form of manifest string.%
  1334.              % Bad character before '%%'.");
  1335.              state := 0;
  1336.           end;
  1337.            end;
  1338.         end;
  1339.         next_char;
  1340.         skip_comments;
  1341.      end;
  1342.       end;
  1343.  
  1344.    a_real: BOOLEAN is
  1345.       local
  1346.      state, l, c: INTEGER;
  1347.      -- state 0  : reading integral part.
  1348.      -- state 1  : reading integral part after '_'.
  1349.      -- state 2  : reading integral part after '_' and 1 digit.
  1350.      -- state 3  : reading integral part after '_' and 2 digits.
  1351.      -- state 4  : '.' read and not empty integral_part.
  1352.      -- state 5  : '.' read and empty integral_part.
  1353.      -- state 6  : reading frac_part.
  1354.      -- state 7  : reading frac_part after '_'.
  1355.      -- state 8  : reading frac_part after '_' and 1 digit.
  1356.      -- state 9  : reading frac_part after '_' and 2 digits.
  1357.      -- state 10 : 'E' or 'e' read.
  1358.      -- state 11 : reading exponent.
  1359.      -- state 12 : happy end.
  1360.      -- state 13 : error end.
  1361.       do
  1362.      if cc.is_digit or else cc = '.' then
  1363.         from
  1364.            l := line;
  1365.            c := column;
  1366.            tmp_string.clear;
  1367.            if cc = '.' then
  1368.           tmp_string.append(fz_59);
  1369.           state := 5;
  1370.            else
  1371.           tmp_string.extend(cc);
  1372.            end;
  1373.         until
  1374.            state > 11
  1375.         loop
  1376.            next_char;
  1377.            inspect
  1378.           state
  1379.            when 0 then
  1380.           inspect
  1381.              cc
  1382.           when '0' .. '9' then
  1383.              tmp_string.extend(cc);
  1384.           when '.' then
  1385.              tmp_string.extend('.');
  1386.              state := 4;
  1387.           else
  1388.              state := 13;
  1389.           end;
  1390.            when 1 then
  1391.           inspect
  1392.              cc
  1393.           when '0'..'9' then
  1394.              tmp_string.extend(cc);
  1395.              state := 2;
  1396.           else
  1397.              fcp(em9);
  1398.           end;
  1399.            when 2 then
  1400.           inspect
  1401.              cc
  1402.           when '0'..'9' then
  1403.              tmp_string.extend(cc);
  1404.              state := 3;
  1405.           else
  1406.              fcp(em9);
  1407.           end;
  1408.            when 3 then
  1409.           inspect
  1410.              cc
  1411.           when '0'..'9' then
  1412.              tmp_string.extend(cc);
  1413.              state := 0;
  1414.           else
  1415.              fcp(em9);
  1416.           end;
  1417.            when 4 then
  1418.           inspect
  1419.              cc
  1420.           when '0'..'9' then
  1421.              tmp_string.extend(cc);
  1422.              state := 6;
  1423.           when 'E','e' then
  1424.              tmp_string.extend('E');
  1425.              state := 10;
  1426.           else
  1427.              state := 12;
  1428.           end;
  1429.            when 5 then
  1430.           inspect
  1431.              cc
  1432.           when '0'..'9' then
  1433.              tmp_string.extend(cc);
  1434.              state := 6;
  1435.           else
  1436.              state := 13;
  1437.           end;
  1438.            when 6 then
  1439.           inspect
  1440.              cc
  1441.           when '0'..'9' then
  1442.              tmp_string.extend(cc);
  1443.           when 'E','e' then
  1444.              tmp_string.extend('E');
  1445.              state := 10;
  1446.           when '_' then
  1447.              state := 7;
  1448.           else
  1449.              state := 12;
  1450.           end;
  1451.            when 7 then
  1452.           inspect
  1453.              cc
  1454.           when '0'..'9' then
  1455.              tmp_string.extend(cc);
  1456.              state := 8;
  1457.           else
  1458.              fcp(em1);
  1459.           end;
  1460.            when 8 then
  1461.           inspect
  1462.              cc
  1463.           when '0'..'9' then
  1464.              tmp_string.extend(cc);
  1465.              state := 9;
  1466.           else
  1467.              fcp(em1);
  1468.           end;
  1469.            when 9 then
  1470.           inspect
  1471.              cc
  1472.           when '0'..'9' then
  1473.              tmp_string.extend(cc);
  1474.              state := 6;
  1475.           else
  1476.              fcp(em1);
  1477.           end;
  1478.            when 10 then
  1479.           inspect
  1480.              cc
  1481.           when '+' then
  1482.              state := 11;
  1483.           when '-' then
  1484.              tmp_string.extend('-');
  1485.              state := 11;
  1486.           when '0'..'9' then
  1487.              tmp_string.extend(cc);
  1488.              state := 11
  1489.           else
  1490.              fcp("Exponent of a real value expected.");
  1491.              state := 13;
  1492.           end;
  1493.            else -- state = 11
  1494.           inspect
  1495.              cc
  1496.           when '0'..'9' then
  1497.              tmp_string.extend(cc);
  1498.           else
  1499.              state := 12;
  1500.           end;
  1501.            end;
  1502.         end;
  1503.         if state = 12 then
  1504.            !!last_real_constant.make(pos(l,c),tmp_string.twin);
  1505.            Result := true;
  1506.            skip_comments;
  1507.         else
  1508.            go_back_at(l,c);
  1509.         end;
  1510.      end;
  1511.       end;
  1512.  
  1513.    a_retry: BOOLEAN is
  1514.       do
  1515.      if a_keyword(fz_retry) then
  1516.         if not in_rescue then
  1517.            error(pos(start_line,start_column),
  1518.              "%"retry%" cannot be outside of a rescue clause.");
  1519.         end;
  1520.         !E_RETRY!last_instruction.make(pos(start_line,start_column));
  1521.         Result := true;
  1522.      end;
  1523.       end;
  1524.  
  1525.    a_actual: BOOLEAN is
  1526.      --++ actual -> expression |
  1527.      --++           "$" identifier
  1528.      --++
  1529.       do
  1530.      if skip1('%D') then
  1531.         if a_identifier then
  1532.            if a_result or else a_void or else a_current then
  1533.           eh.add_position(last_expression.start_position);
  1534.           fatal_error(fz_vuar4);
  1535.            else
  1536.           !ADDRESS_OF!last_expression.make(tmp_name.to_simple_feature_name);
  1537.           Result:= true;
  1538.            end;
  1539.         else
  1540.            fcp(fz_vuar4);
  1541.         end;
  1542.      elseif a_expression then
  1543.         Result := true;
  1544.      end;
  1545.       end;
  1546.  
  1547.    a_actuals: EFFECTIVE_ARG_LIST is
  1548.      --++ actuals -> "(" {actual "," ...} ")"
  1549.      --++
  1550.       local
  1551.      first_one: EXPRESSION;
  1552.      remainder: FIXED_ARRAY[EXPRESSION];
  1553.       do
  1554.      if skip1('(') then
  1555.         from
  1556.         until
  1557.            not a_actual
  1558.         loop
  1559.            if first_one = Void then
  1560.           first_one := last_expression;
  1561.            else
  1562.           if remainder = Void then
  1563.              !!remainder.with_capacity(4);
  1564.           end;
  1565.           remainder.add_last(last_expression);
  1566.            end;
  1567.            if not skip1(',') and then cc /= ')' then
  1568.         wcp(em5);
  1569.            end;
  1570.         end;
  1571.         if first_one = Void then
  1572.            wcp("Empty argument list (deleted).");
  1573.         else
  1574.            !!Result.make_n(first_one,remainder);
  1575.         end;
  1576.         if not skip1(')') then
  1577.            fcp("')' expected to end arguments list.");
  1578.         end;
  1579.      end;
  1580.       end;
  1581.  
  1582.    a_after_a_dot(do_instruction: BOOLEAN; target: EXPRESSION) is
  1583.      --++ after_a_dot -> identifier [actuals] ["." after_a_dot]
  1584.      --++
  1585.       require
  1586.      target /= Void
  1587.       local
  1588.      sfn: SIMPLE_FEATURE_NAME;
  1589.      eal: EFFECTIVE_ARG_LIST;
  1590.       do
  1591.      if a_identifier then
  1592.         if a_result or else a_void or else a_current then
  1593.            error(last_expression.start_position,
  1594.              "This name must not appear after a dot.");
  1595.         end;
  1596.         sfn := tmp_name.to_simple_feature_name;
  1597.         eal := a_actuals;
  1598.         a_r10(do_instruction,target,sfn,eal);
  1599.      else
  1600.         fcp("Identifier expected after a dot.");
  1601.      end;
  1602.       end;
  1603.  
  1604.    a_assignment_or_call: BOOLEAN is
  1605.      --++ assignment_or_call -> "(" expression ")" r10 |
  1606.      --++                       precursor_call |
  1607.      --++                       "Current" r10 |
  1608.      --++                       "Result" r10 |
  1609.      --++                       local_variable r10 |
  1610.      --++                       formal_argument r10 |
  1611.      --++                       writable ":=" expression |
  1612.      --++                       writable "?=" expression |
  1613.      --++                       identifier procedure_call
  1614.      --++
  1615.       do
  1616.      if skip1('(') and then a_expression then
  1617.         Result := true;
  1618.         if skip1(')') then
  1619.            a_r10(true,last_expression,Void,Void);
  1620.         else
  1621.            fcp("')' expected.");
  1622.         end;
  1623.      elseif a_precursor(true) then
  1624.         Result := true;
  1625.      elseif a_identifier then
  1626.         Result := true;
  1627.         if skip2(':','=') then
  1628.            a_assignment_aux(true);
  1629.         elseif skip2('?','=') then
  1630.            a_assignment_aux(false);
  1631.         elseif a_current or else a_result or else a_local_variable
  1632.            or else a_argument then
  1633.            a_r10(true,last_expression,Void,Void);
  1634.         else
  1635.            a_procedure_call;
  1636.         end;
  1637.      end;
  1638.       end;
  1639.  
  1640.    a_assignment_aux(regular: BOOLEAN) is
  1641.       local
  1642.      writable, rhs: EXPRESSION;
  1643.       do
  1644.      if a_current then
  1645.         eh.add_position(last_expression.start_position);
  1646.         fatal_error("Must not affect `Current'.");
  1647.      elseif a_void then
  1648.         eh.add_position(tmp_name.start_position);
  1649.         fatal_error("Must not affect `Void'.");
  1650.      elseif a_argument then
  1651.         eh.add_position(last_expression.start_position);
  1652.         fatal_error("Must not affect a formal argument.");
  1653.      else
  1654.         if tmp_name.is_result then
  1655.            writable := last_result;
  1656.         elseif a_local_variable then
  1657.            writable := last_expression;
  1658.         else
  1659.            writable := tmp_name.to_simple_feature_name;
  1660.         end;
  1661.         if a_expression then
  1662.            rhs := last_expression;
  1663.            if regular then
  1664.           !ASSIGNMENT!last_instruction.make(writable,rhs);
  1665.            else
  1666.           !REVERSE_ASSIGNMENT!last_instruction.make(writable,rhs);
  1667.            end;
  1668.         else
  1669.            fcp("Right hand side expression expected for assignment.");
  1670.         end;
  1671.      end;
  1672.       end;
  1673.  
  1674.    a_assertion: ARRAY[ASSERTION] is
  1675.      --++ assertion -> {assertion_clause ";" ...}
  1676.      --++ assertion_clause -> [identifier ":"] [expression] [comment]
  1677.      --++
  1678.       local
  1679.      tag: like last_tag_mark;
  1680.      expression: like last_expression;
  1681.      assertion: ASSERTION;
  1682.      state: INTEGER;
  1683.      -- state 0 : nothing read.
  1684.      -- state 1 : read a `tag'.
  1685.      -- state 2 : read an `expression'.
  1686.      -- state 3 : read a `tag' and an `expression'.
  1687.      -- state 4 : end;
  1688.       do
  1689.      from
  1690.      until
  1691.         state > 3
  1692.      loop
  1693.         inspect
  1694.            state
  1695.         when 0 then
  1696.            if cc = ';' then
  1697.           wcp(fz_desc);
  1698.           ok := skip1(';');
  1699.           if last_comments /= Void then
  1700.              !!assertion.make(Void,Void,get_comments);
  1701.              if Result = Void then
  1702.             !!Result.with_capacity(2,1);
  1703.              end;
  1704.              Result.add_last(assertion);
  1705.           end;
  1706.            elseif a_tag_mark then
  1707.           tag := last_tag_mark;
  1708.           state := 1;
  1709.            elseif a_expression then
  1710.           expression := last_expression;
  1711.           state := 2;
  1712.            else
  1713.           state := 4;
  1714.            end;
  1715.         when 1 then
  1716.            if skip1(';') then
  1717.           !!assertion.make(tag,Void,get_comments);
  1718.           if Result = Void then
  1719.              !!Result.with_capacity(2,1);
  1720.           end;
  1721.           Result.add_last(assertion);
  1722.           state := 0;
  1723.            elseif a_tag_mark then
  1724.           !!assertion.make(tag,Void,get_comments);
  1725.           if Result = Void then
  1726.              !!Result.with_capacity(2,1);
  1727.           end;
  1728.           Result.add_last(assertion);
  1729.           tag := last_tag_mark;
  1730.            elseif a_expression then
  1731.           expression := last_expression;
  1732.           state := 3;
  1733.            else
  1734.           !!assertion.make(tag,Void,get_comments);
  1735.           if Result = Void then
  1736.              !!Result.with_capacity(2,1);
  1737.           end;
  1738.           Result.add_last(assertion);
  1739.           state := 4;
  1740.            end;
  1741.         when 2 then
  1742.            if skip1(';') then
  1743.           !!assertion.make(Void,expression,get_comments);
  1744.           if Result = Void then
  1745.              !!Result.with_capacity(2,1);
  1746.           end;
  1747.           Result.add_last(assertion);
  1748.           state := 0;
  1749.            elseif a_tag_mark then
  1750.           !!assertion.make(Void,expression,get_comments);
  1751.           if Result = Void then
  1752.              !!Result.with_capacity(2,1);
  1753.           end;
  1754.           Result.add_last(assertion);
  1755.           tag := last_tag_mark;
  1756.           state := 1;
  1757.            elseif a_expression then
  1758.           !!assertion.make(Void,expression,get_comments);
  1759.           if Result = Void then
  1760.              !!Result.with_capacity(2,1);
  1761.           end;
  1762.           Result.add_last(assertion);
  1763.           expression := last_expression;
  1764.           state := 2;
  1765.            else
  1766.           !!assertion.make(Void,expression,get_comments);
  1767.           if Result = Void then
  1768.              !!Result.with_capacity(2,1);
  1769.           end;
  1770.           Result.add_last(assertion);
  1771.           state := 4;
  1772.            end;
  1773.         else -- state = 3
  1774.            if skip1(';') then
  1775.           !!assertion.make(tag,expression,get_comments);
  1776.           if Result = Void then
  1777.              !!Result.with_capacity(2,1);
  1778.           end;
  1779.           Result.add_last(assertion);
  1780.           state := 0;
  1781.            elseif a_tag_mark then
  1782.           !!assertion.make(tag,expression,get_comments);
  1783.           if Result = Void then
  1784.              !!Result.with_capacity(2,1);
  1785.           end;
  1786.           Result.add_last(assertion);
  1787.           tag := last_tag_mark;
  1788.           state := 1;
  1789.            elseif a_expression then
  1790.           !!assertion.make(tag,expression,get_comments);
  1791.           if Result = Void then
  1792.              !!Result.with_capacity(2,1);
  1793.           end;
  1794.           Result.add_last(assertion);
  1795.           expression := last_expression;
  1796.           state := 2;
  1797.            else
  1798.           !!assertion.make(tag,expression,get_comments);
  1799.           if Result = Void then
  1800.              !!Result.with_capacity(2,1);
  1801.           end;
  1802.           Result.add_last(assertion);
  1803.           state := 4;
  1804.            end;
  1805.         end;
  1806.      end;
  1807.       end;
  1808.  
  1809.    a_base_type: BOOLEAN is
  1810.      --++ base_type -> "ANY" | ARRAY "[" type "]" | "BOOLEAN" |
  1811.      --++         "CHARACTER" | "DOUBLE" | "INTEGER" | "NONE" |
  1812.      --++         "POINTER" | "REAL" | "STRING"
  1813.      --++
  1814.       local
  1815.      sp: POSITION;
  1816.       do
  1817.      Result := true;
  1818.      if a_keyword(as_any) then
  1819.         !TYPE_ANY!last_base_type.make(pos(start_line,start_column));
  1820.      elseif a_keyword(as_array) then
  1821.         sp := pos(start_line,start_column);
  1822.         if skip1('[') and then a_type and then skip1(']') then
  1823.            check
  1824.           last_type /= Void
  1825.            end;
  1826.            !TYPE_ARRAY!last_base_type.make(sp,last_type);
  1827.         else
  1828.            fcp("Bad use of predefined type ARRAY.");
  1829.         end;
  1830.      elseif a_keyword(as_native_array) then
  1831.         sp := pos(start_line,start_column);
  1832.         if skip1('[') and then a_type and then skip1(']') then
  1833.            check
  1834.           last_type /= Void
  1835.            end;
  1836.            !TYPE_NATIVE_ARRAY!last_base_type.make(sp,last_type);
  1837.         else
  1838.            fcp("Bad use of predefined type NATIVE_ARRAY.");
  1839.         end;
  1840.      elseif a_keyword(as_boolean) then
  1841.         !TYPE_BOOLEAN!last_base_type.make(pos(start_line,start_column));
  1842.      elseif a_keyword(as_character) then
  1843.         !TYPE_CHARACTER!last_base_type.make(pos(start_line,start_column));
  1844.      elseif a_keyword(as_double) then
  1845.         !TYPE_DOUBLE!last_base_type.make(pos(start_line,start_column));
  1846.      elseif a_keyword(as_integer) then
  1847.         !TYPE_INTEGER!last_base_type.make(pos(start_line,start_column));
  1848.      elseif a_keyword(as_none) then
  1849.         !TYPE_NONE!last_base_type.make(pos(start_line,start_column));
  1850.      elseif a_keyword(as_pointer) then
  1851.         !TYPE_POINTER!last_base_type.make(pos(start_line,start_column));
  1852.      elseif a_keyword(as_real) then
  1853.         !TYPE_REAL!last_base_type.make(pos(start_line,start_column));
  1854.      elseif a_keyword(as_string) then
  1855.         !TYPE_STRING!last_base_type.make(pos(start_line,start_column));
  1856.      else
  1857.         Result := false;
  1858.      end;
  1859.       end;
  1860.  
  1861.    a_binary(sp: POSITION): BOOLEAN is
  1862.      --++ binary -> "<=" | ">=" | "//" | "\\" |
  1863.      --++           "+" | "-" | "*" | "/" | "<" | ">" | "^" |
  1864.      --++           xor" | "implies" | "and then" | "and" | "or else" | "or"
  1865.      --++
  1866.       do
  1867.      Result := true;
  1868.      if skip2('<','=') then
  1869.         !!last_binary.make(as_le,sp);
  1870.      elseif skip2('>','=') then
  1871.         !!last_binary.make(as_ge,sp);
  1872.      elseif skip2('/','/') then
  1873.         !!last_binary.make(as_slash_slash,sp);
  1874.      elseif skip2('\','\') then
  1875.         !!last_binary.make(as_backslash_backslash,sp);
  1876.      elseif skip1('+') then
  1877.         !!last_binary.make(as_plus,sp);
  1878.      elseif skip1('-') then
  1879.         !!last_binary.make(as_minus,sp);
  1880.      elseif skip1('*') then
  1881.         !!last_binary.make(as_muls,sp);
  1882.      elseif skip1('/') then
  1883.         !!last_binary.make(as_slash,sp);
  1884.      elseif skip1('>') then
  1885.         !!last_binary.make(as_gt,sp);
  1886.      elseif skip1('<') then
  1887.         !!last_binary.make(as_lt,sp);
  1888.      elseif skip1('^') then
  1889.         !!last_binary.make(as_pow,sp);
  1890.      elseif a_keyword(as_xor) then
  1891.         !!last_binary.make(as_xor,sp);
  1892.      elseif a_keyword(as_implies) then
  1893.         !!last_binary.make(as_implies,sp)
  1894.      elseif a_keyword(as_and) then
  1895.         if a_keyword(fz_then) then
  1896.            !!last_binary.make(as_and_then,sp);
  1897.         else
  1898.            !!last_binary.make(as_and,sp);
  1899.         end;
  1900.      elseif a_keyword(as_or) then
  1901.         if a_keyword(fz_else) then
  1902.            !!last_binary.make(as_or_else,sp);
  1903.         else
  1904.            !!last_binary.make(as_or,sp);
  1905.         end;
  1906.      else
  1907.         last_binary := Void;
  1908.         Result := false;
  1909.      end;
  1910.       end;
  1911.  
  1912.    a_boolean_constant: BOOLEAN is
  1913.      --++ boolean_constant -> "true" | "false"
  1914.      --++
  1915.       do
  1916.      if a_keyword(fz_true) then
  1917.         !E_TRUE!last_boolean_constant.make(pos(start_line,start_column));
  1918.         Result := true;
  1919.      elseif a_keyword(fz_false) then
  1920.         !E_FALSE!last_boolean_constant.make(pos(start_line,start_column));
  1921.         Result := true;
  1922.      end;
  1923.       end;
  1924.  
  1925.    a_character_or_integer: BOOLEAN is
  1926.      --++ character_or_integer -> character_constant |
  1927.      --++                         integer_constant
  1928.      --++
  1929.       do
  1930.      if a_character_constant then
  1931.         last_character_or_integer := last_character_constant;
  1932.         Result := true;
  1933.      elseif a_integer_constant then
  1934.         last_character_or_integer := last_integer_constant;
  1935.         Result := true;
  1936.      end;
  1937.       end;
  1938.  
  1939.    a_check: BOOLEAN is
  1940.      --++ check -> "check" assertion "end"
  1941.      --++
  1942.       local
  1943.      sp: POSITION;
  1944.      hc: COMMENT;
  1945.      al: ARRAY[ASSERTION];
  1946.       do
  1947.      if a_keyword(fz_check) then
  1948.         sp := pos(start_line,start_column);
  1949.         hc := get_comments;
  1950.         al := a_assertion;
  1951.         if not a_keyword(fz_end) then
  1952.            eh.add_position(sp);
  1953.            fcp("Keyword %"end%" expected at the end of check clause.");
  1954.         end;
  1955.         if hc /= Void or else al /= Void then
  1956.            !E_CHECK!last_instruction.make(sp,hc,al);
  1957.            Result := true;
  1958.         elseif skip1(';') then
  1959.         end;
  1960.      end;
  1961.       end;
  1962.  
  1963.    a_class_declaration is
  1964.      --++ class_declaration -> [indexing]
  1965.      --++                      ["expanded" | "deferred"]
  1966.      --++                      "class" base_class_name
  1967.      --++                      ["[" formal_generic_list "]"]
  1968.      --++                      [comment]
  1969.      --++                      ["obsolete" manifest_string]
  1970.      --++                      ["inherit" parent_list]
  1971.      --++                      {"creation" creation_clause ...}
  1972.      --++                      {"create" creation_clause ...}
  1973.      --++                      {"feature" feature_clause ...}
  1974.      --++                      ["invariant" assertion]
  1975.      --++                      "end"
  1976.      --++
  1977.       local
  1978.      sp: POSITION;
  1979.      hc: COMMENT;
  1980.      al: ARRAY[ASSERTION];
  1981.      drop_comments_save: BOOLEAN;
  1982.       do
  1983.      a_indexing;
  1984.      if a_keyword(fz_deferred) then
  1985.         last_base_class.set_is_deferred;
  1986.      end;
  1987.      if a_keyword(fz_expanded) then
  1988.         last_base_class.set_is_expanded;
  1989.         if a_keyword(fz_deferred) then
  1990.            last_base_class.set_is_deferred;
  1991.         end;
  1992.      end;
  1993.      last_base_class.set_heading_comment1(get_comments);
  1994.      if not a_keyword(fz_class) then
  1995.         fcp("Keyword %"class%" expected.");
  1996.      end;
  1997.      a_base_class_name1;
  1998.      a_formal_generic_list;
  1999.      if a_keyword(fz_obsolete) then
  2000.         if a_manifest_string then
  2001.            last_base_class.set_obsolete_type_string(last_manifest_string);
  2002.         else
  2003.            fcp("Manifest string expected for %"obsolete%" clause.");
  2004.         end;
  2005.      end;
  2006.      last_base_class.set_heading_comment2(get_comments);
  2007.      if a_keyword(fz_inherit) then
  2008.         a_parent_list(pos(start_line,start_column),get_comments);
  2009.      end;
  2010.      from
  2011.      until
  2012.         not (a_keyword(fz_creation) or else a_keyword(fz_create))
  2013.      loop
  2014.         a_creation_clause(pos(start_line,start_column));
  2015.      end;
  2016.      from
  2017.      until
  2018.         not a_keyword(fz_feature)
  2019.      loop
  2020.         a_feature_clause;
  2021.      end;
  2022.      drop_comments_save := drop_comments;
  2023.      drop_comments := false;
  2024.      if a_keyword(fz_invariant) then
  2025.         sp := pos(start_line,start_column);
  2026.         hc := get_comments;
  2027.         al := a_assertion;
  2028.         last_base_class.set_invariant(sp,hc,al);
  2029.      end;
  2030.      if a_keyword(fz_end) or else last_keyword = fz_end then
  2031.         if cc = ';' then
  2032.            wcp(fz_desc);
  2033.            ok := skip1(';');
  2034.         end;
  2035.         last_base_class.set_end_comment(get_comments);
  2036.         if cc /= end_of_text then
  2037.            fcp("End of text expected.");
  2038.         end;
  2039.      else
  2040.         fcp("Keyword %"end%" expected at the end of a class.");
  2041.      end;
  2042.      drop_comments := drop_comments_save;
  2043.       end;
  2044.  
  2045.    a_class_type: BOOLEAN is
  2046.      --++ class_type -> base_type |
  2047.      --++               base_class_name ["[" {type "," ...} "]"]
  2048.      --++
  2049.       local
  2050.      state: INTEGER;
  2051.      base_class_name: CLASS_NAME;
  2052.      generic_list: ARRAY[TYPE];
  2053.      -- state 0 : `base_class_name' read.
  2054.      -- state 1 : waiting next generic argument.
  2055.      -- state 2 : waiting ',' or ']'.
  2056.      -- state 3 : end.
  2057.       do
  2058.      if a_base_type then
  2059.         last_class_type := last_base_type;
  2060.         Result := true;
  2061.      elseif a_base_class_name then
  2062.         from
  2063.            Result := true;
  2064.            base_class_name := last_class_name;
  2065.         until
  2066.            state > 2
  2067.         loop
  2068.            inspect
  2069.           state
  2070.            when 0 then
  2071.           if skip1('[') then
  2072.              state := 1;
  2073.           else
  2074.              !TYPE_CLASS!last_class_type.make(base_class_name);
  2075.              state := 3;
  2076.           end;
  2077.            when 1 then
  2078.           if a_type then
  2079.              if generic_list = Void then
  2080.             !!generic_list.with_capacity(2,1);
  2081.              end;
  2082.              generic_list.add_last(last_type);
  2083.              state := 2;
  2084.           elseif cc = ',' then
  2085.              wcp(em12);
  2086.              ok := skip1(',');
  2087.           elseif cc = ']' then
  2088.              state := 2;
  2089.           else
  2090.              fcp(em16);
  2091.              state := 2;
  2092.           end;
  2093.            else -- state = 2
  2094.           if skip1(',') then
  2095.              state := 1;
  2096.           elseif cc = ']' then
  2097.              if generic_list = Void then
  2098.             wcp("Empty generic list (deleted).");
  2099.             !TYPE_CLASS!last_class_type.make(base_class_name);
  2100.              else
  2101.             !TYPE_GENERIC!last_class_type.make(base_class_name,generic_list);
  2102.              end;
  2103.              ok := skip1(']');
  2104.              state := 3;
  2105.           elseif a_type then
  2106.              if generic_list = Void then
  2107.             !!generic_list.with_capacity(2,1);
  2108.              end;
  2109.              generic_list.add_last(last_type);
  2110.              warning(last_type.start_position,em5);
  2111.           else
  2112.              fcp("Bad generic list.");
  2113.              state := 3;
  2114.           end;
  2115.            end;
  2116.         end;
  2117.      end;
  2118.       end;
  2119.  
  2120.    a_clients: CLIENT_LIST is
  2121.      --++ clients -> "{" { base_class_name "," ... } "}"
  2122.      --++
  2123.       local
  2124.      sp: POSITION;
  2125.      list: CLASS_NAME_LIST;
  2126.      state: INTEGER;
  2127.      -- state 0 : waiting a base_class_name or "}" if empty list.
  2128.      -- state 1 : waiting a base_class_name after a ",".
  2129.      -- state 2 : waiting "," or "}" to end list.
  2130.      -- state 3 : error.
  2131.      -- state 4 : end.
  2132.       do
  2133.      if skip1('{') then
  2134.         from
  2135.            sp := pos(start_line,start_column);
  2136.         until
  2137.            state > 3
  2138.         loop
  2139.            inspect
  2140.           state
  2141.            when 0 then
  2142.           if a_base_class_name then
  2143.              !!list.make_1(last_class_name);
  2144.              state := 2;
  2145.           elseif skip1('}') then
  2146.              state := 4;
  2147.           elseif cc = ',' then
  2148.              wcp(em7);
  2149.              ok := skip1(',');
  2150.           else
  2151.              state := 3;
  2152.           end;
  2153.            when 1 then
  2154.           if a_base_class_name then
  2155.              list.add_last(last_class_name);
  2156.              state := 2;
  2157.           elseif cc = ',' then
  2158.              wcp(em7);
  2159.              ok := skip1(',');
  2160.           elseif cc = '}' then
  2161.              wcp("Unexpected bracket.");
  2162.              ok := skip1('}');
  2163.              state := 4;
  2164.           else
  2165.              state := 3;
  2166.           end;
  2167.            when 2 then
  2168.           if skip1(',') then
  2169.              state := 1;
  2170.           elseif skip1('}') then
  2171.              state := 4;
  2172.           elseif a_base_class_name then
  2173.              warning(last_class_name.start_position,em5);
  2174.              list.add_last(last_class_name);
  2175.           else
  2176.              state := 3;
  2177.           end;
  2178.            else -- state = 3
  2179.           fcp(em11);
  2180.           state := 4;
  2181.            end;
  2182.         end;
  2183.         !!Result.make(sp,list);
  2184.      else
  2185.         !!Result.omitted;
  2186.      end;
  2187.       ensure
  2188.      Result /= Void
  2189.       end;
  2190.  
  2191.    a_compound1: COMPOUND is
  2192.      --++ compound -> {instruction ";" ...}
  2193.      --++
  2194.       local
  2195.      hc: COMMENT;
  2196.      instruction, first_one: INSTRUCTION;
  2197.      remainder: FIXED_ARRAY[INSTRUCTION];
  2198.       do
  2199.      from
  2200.         hc := get_comments;
  2201.         from
  2202.         until
  2203.            cc /= ';'
  2204.         loop
  2205.            wcp(fz_desc);
  2206.            ok := skip1(';');
  2207.         end;
  2208.      until
  2209.         not a_instruction or else nb_errors > 0
  2210.      loop
  2211.         instruction := last_instruction;
  2212.         check
  2213.            instruction /= Void;
  2214.         end;
  2215.         if cc = '(' then
  2216.            wcp(em6);
  2217.         end;
  2218.         from
  2219.            ok := skip1(';');
  2220.         until
  2221.            cc /= ';'
  2222.         loop
  2223.            wcp(fz_desc);
  2224.            ok := skip1(';');
  2225.         end;
  2226.         if nb_errors = 0 then
  2227.            instruction := instruction.add_comment(get_comments);
  2228.            if first_one = Void then
  2229.           first_one := instruction;
  2230.            else
  2231.           if remainder = Void then
  2232.              !!remainder.with_capacity(4);
  2233.           end;
  2234.           remainder.add_last(instruction);
  2235.            end;
  2236.         end;
  2237.      end;
  2238.      if hc /= Void or else first_one /= Void then
  2239.         !!Result.make(hc,first_one,remainder);
  2240.      end;
  2241.       end;
  2242.  
  2243.    a_compound2(compound_of, terminator: STRING): COMPOUND is
  2244.      -- Like a_compound1 but stop when `terminator' is encountered.
  2245.       local
  2246.      hc: COMMENT;
  2247.      instruction, first_one: INSTRUCTION;
  2248.      remainder: FIXED_ARRAY[INSTRUCTION];
  2249.       do
  2250.      from
  2251.         hc := get_comments;
  2252.         from
  2253.         until
  2254.            cc /= ';'
  2255.         loop
  2256.            wcp(fz_desc);
  2257.            ok := skip1(';');
  2258.         end;
  2259.      until
  2260.         not a_instruction or else nb_errors > 0
  2261.      loop
  2262.         instruction := last_instruction;
  2263.         check
  2264.            instruction /= Void;
  2265.         end;
  2266.         if cc = '(' then
  2267.            wcp(em6);
  2268.         end;
  2269.         from
  2270.            ok := skip1(';');
  2271.         until
  2272.            cc /= ';'
  2273.         loop
  2274.            wcp(fz_desc);
  2275.            ok := skip1(';');
  2276.         end;
  2277.         if nb_errors = 0 then
  2278.            instruction := instruction.add_comment(get_comments);
  2279.            if first_one = Void then
  2280.           first_one := instruction;
  2281.            else
  2282.           if remainder = Void then
  2283.              !!remainder.with_capacity(4);
  2284.           end;
  2285.           remainder.add_last(instruction);
  2286.            end;
  2287.         end;
  2288.      end;
  2289.      if not a_keyword(terminator) then
  2290.         eh.append("In compound (");
  2291.         eh.append(compound_of);
  2292.         eh.append("). Instruction or keyword %"");
  2293.         eh.append(terminator);
  2294.         fcp("%" expected.");
  2295.      end;
  2296.      if hc /= Void or else first_one /= Void then
  2297.         !!Result.make(hc,first_one,remainder);
  2298.      end;
  2299.       end;
  2300.  
  2301.    a_conditional: BOOLEAN is
  2302.      --++ conditional -> "if" then_part_list ["else" compound] "end"
  2303.      --++
  2304.       local
  2305.      ifthenelse: IFTHENELSE;
  2306.       do
  2307.      if a_keyword(fz_if) then
  2308.         Result := true;
  2309.         !!ifthenelse.make(pos(start_line,start_column));
  2310.         a_then_part_list(ifthenelse);
  2311.         if a_keyword(fz_else) then
  2312.            ifthenelse.set_else_compound(a_compound2("else part",fz_end));
  2313.         else
  2314.            if not a_keyword(fz_end) then
  2315.           wcp("Keyword %"end%" added.");
  2316.            end;
  2317.         end;
  2318.         last_instruction := ifthenelse;
  2319.      end;
  2320.       end;
  2321.  
  2322.    a_creation: BOOLEAN is
  2323.      --++ creation -> "!"[type]"!" writable ["." procedure_name [actuals]]
  2324.      --++
  2325.       local
  2326.      sp: POSITION;
  2327.      type: TYPE;
  2328.      writable: EXPRESSION;
  2329.      procedure_name: SIMPLE_FEATURE_NAME;
  2330.      call: PROC_CALL;
  2331.       do
  2332.      if skip1('!') then
  2333.         Result := true;
  2334.         sp := pos(start_line,start_column);
  2335.         if a_type then
  2336.            type := last_type;
  2337.            if type.is_anchored then
  2338.           warning(type.start_position,em20);
  2339.            end;
  2340.            if not skip1('!') then
  2341.           fcp("Bad creation instruction ('!' expected).");
  2342.            end;
  2343.         elseif skip1('!') then
  2344.         else
  2345.            fcp("Bad creation instruction (type or '!' expected).");
  2346.         end;
  2347.         writable := mandatory_writable;
  2348.         if skip1('.') then
  2349.            if a_identifier then
  2350.           procedure_name := tmp_name.to_simple_feature_name;
  2351.           if cc = '(' then
  2352.              call := to_proc_call(writable,procedure_name,a_actuals);
  2353.           else
  2354.              !PROC_CALL_0!call.make(writable,procedure_name);
  2355.           end;
  2356.            else
  2357.           fcp(em23);
  2358.            end;
  2359.         end;
  2360.         if type = Void and then call = Void then
  2361.            !CREATION_CALL_1!last_instruction.make(sp,writable);
  2362.         elseif type /= Void and then call = Void then
  2363.            !CREATION_CALL_2!last_instruction.make(sp,type,writable);
  2364.         elseif type = Void and then call /= Void then
  2365.            !CREATION_CALL_3!last_instruction.make(sp,writable,call);
  2366.         else
  2367.            !CREATION_CALL_4!last_instruction.make(sp,type,writable,call);
  2368.         end;
  2369.      end;
  2370.       end;
  2371.  
  2372.    a_create_instruction: BOOLEAN is
  2373.      --++ create -> ["{" type "}"] writable ["." procedure_name [actuals]]
  2374.      --++
  2375.      -- Note: this is only syntactic sugar to accept this new 
  2376.      -- notation (which is by now pretty_printed in the good old 
  2377.      -- notation ;-).
  2378.       local
  2379.      sp: POSITION;
  2380.      type: TYPE;
  2381.      writable: EXPRESSION;
  2382.      procedure_name: SIMPLE_FEATURE_NAME;
  2383.      call: PROC_CALL;
  2384.       do
  2385.      if a_keyword(fz_create) then
  2386.         Result := true;
  2387.         sp := pos(start_line,start_column);
  2388. -- ***
  2389. --        eh.add_position(sp);
  2390. --        eh.append("New create instruction used (temporary warning %
  2391. --                      %because this new syntax may be ambigous).");
  2392. --        eh.print_as_warning;
  2393. -- ***
  2394.         if skip1('{') then
  2395.            if a_type then
  2396.           type := last_type;
  2397.           if type.is_anchored then
  2398.              warning(type.start_position,em20);
  2399.           end;
  2400.           if not skip1('}') then
  2401.              fcp("Bad create instruction ('}' expected).");
  2402.           end;
  2403.            else
  2404.           fcp("Bad create instruction (type expected).");
  2405.            end;
  2406.         end;
  2407.         writable := mandatory_writable;
  2408.         if skip1('.') then
  2409.            if a_identifier then
  2410.           procedure_name := tmp_name.to_simple_feature_name;
  2411.           if cc = '(' then
  2412.              call := to_proc_call(writable,procedure_name,a_actuals);
  2413.           else
  2414.              !PROC_CALL_0!call.make(writable,procedure_name);
  2415.           end;
  2416.            end;
  2417.         end;
  2418.         if type = Void and then call = Void then
  2419.            !CREATION_CALL_1!last_instruction.make(sp,writable);
  2420.         elseif type /= Void and then call = Void then
  2421.            !CREATION_CALL_2!last_instruction.make(sp,type,writable);
  2422.         elseif type = Void and then call /= Void then
  2423.            !CREATION_CALL_3!last_instruction.make(sp,writable,call);
  2424.         else
  2425.            !CREATION_CALL_4!last_instruction.make(sp,type,writable,call);
  2426.         end;
  2427.      end;
  2428.       end;
  2429.    
  2430.    a_creation_clause(sp: POSITION) is
  2431.      --++ creation_clause -> [clients] [comment] feature_list
  2432.      --++
  2433.       local
  2434.      clients: CLIENT_LIST;
  2435.      comments: COMMENT;
  2436.      creation_clause: CREATION_CLAUSE;
  2437.       do
  2438.      clients := a_clients;
  2439.      comments := get_comments;
  2440.      if a_feature_name_list then
  2441.      end;
  2442.      !!creation_clause.make(sp,clients,comments,last_feature_name_list);
  2443.      last_base_class.add_creation_clause(creation_clause);
  2444.       end;
  2445.  
  2446.    a_debug: BOOLEAN is
  2447.      --++ debug -> "debug" "(" {manifest_string "," ...} ")"
  2448.      --++                  compound "end"
  2449.      --++
  2450.       local
  2451.      sp: POSITION;
  2452.      list: ARRAY[MANIFEST_STRING];
  2453.      e_debug: E_DEBUG;
  2454.       do
  2455.      if a_keyword(fz_debug) then
  2456.         sp := pos(start_line,start_column);
  2457.         if skip1('(') then
  2458.            from
  2459.            until
  2460.           not a_manifest_string
  2461.            loop
  2462.           if list = Void then
  2463.              !!list.with_capacity(2,1);
  2464.           end;
  2465.           list.add_last(last_manifest_string);
  2466.           ok := skip1(',');
  2467.            end;
  2468.            if list = Void then
  2469.           wcp("Empty debug key list (deleted).");
  2470.            end;
  2471.            if not skip1(')') then
  2472.           fcp("%")%" expected to end debug string list.");
  2473.            end;
  2474.         end;
  2475.         Result := true;
  2476.         !!e_debug.make(sp,list,a_compound2("debug",fz_end));
  2477.         last_instruction := e_debug;
  2478.         end;
  2479.      end;
  2480.  
  2481.    a_expression: BOOLEAN is
  2482.      --++ expression -> "<<" {Expression "," ...} ">>" |
  2483.      --++               Void |
  2484.      --++               e0
  2485.      --++
  2486.       local
  2487.      sp: POSITION;
  2488.      list: ARRAY[EXPRESSION];
  2489.       do
  2490.      if skip2('<','<') then
  2491.         from
  2492.            Result := true;
  2493.            sp := pos(start_line,start_column);
  2494.         until
  2495.            not a_expression
  2496.         loop
  2497.            if list = Void then
  2498.           !!list.with_capacity(4,1);
  2499.            end;
  2500.            list.add_last(last_expression);
  2501.            ok := skip1(',');
  2502.         end;
  2503.         if not skip2('>','>') then
  2504.            fcp("End of manifest array expected.");
  2505.         end;
  2506.         !MANIFEST_ARRAY!last_expression.make(sp,list);
  2507.      else
  2508.         Result := a_e0;
  2509.      end;
  2510.       end;
  2511.  
  2512.    a_e0: BOOLEAN is
  2513.      --++ e0 -> e1 r1
  2514.      --++
  2515.       do
  2516.      Result := a_e1;
  2517.      if Result then
  2518.         a_r1(last_expression);
  2519.      end;
  2520.       end;
  2521.  
  2522.    a_e1: BOOLEAN is
  2523.      --++ e1 -> e2 r2
  2524.      --++
  2525.       do
  2526.      Result := a_e2;
  2527.      if Result then
  2528.         a_r2(last_expression);
  2529.      end;
  2530.       end;
  2531.  
  2532.    a_e2: BOOLEAN is
  2533.      --++ e2 -> e3 r3
  2534.      --++
  2535.       do
  2536.      Result := a_e3;
  2537.      if Result then
  2538.         a_r3(last_expression);
  2539.      end;
  2540.       end;
  2541.  
  2542.    a_e3: BOOLEAN is
  2543.      --++ e3 -> e4 r4
  2544.      --++
  2545.       do
  2546.      Result := a_e4;
  2547.      if Result then
  2548.         a_r4(last_expression);
  2549.      end;
  2550.       end;
  2551.  
  2552.    a_e4: BOOLEAN is
  2553.      --++ e4 -> e5 r5
  2554.      --++
  2555.       do
  2556.      Result := a_e5;
  2557.      if Result then
  2558.         a_r5(last_expression);
  2559.      end;
  2560.       end;
  2561.  
  2562.    a_e5: BOOLEAN is
  2563.      --++ e5 -> e6 r6
  2564.      --++
  2565.       do
  2566.      Result := a_e6;
  2567.      if Result then
  2568.         a_r6(last_expression);
  2569.      end;
  2570.       end;
  2571.  
  2572.    a_e6: BOOLEAN is
  2573.      --++ e6 -> e7 r7
  2574.      --++
  2575.       do
  2576.      Result := a_e7;
  2577.      if Result then
  2578.         a_r7(last_expression);
  2579.      end;
  2580.       end;
  2581.  
  2582.    a_e7: BOOLEAN is
  2583.      --++ e7 -> e8 r8
  2584.      --++
  2585.       do
  2586.      Result := a_e8;
  2587.      if Result then
  2588.         a_r8(last_expression);
  2589.      end;
  2590.       end;
  2591.  
  2592.    a_e8: BOOLEAN is
  2593.      --++ e8 -> "not" e8 |
  2594.      --++       "+" e8 |
  2595.      --++       "-" e8 |
  2596.      --++       free_operator e8 !
  2597.      --++       e9
  2598.      --++
  2599.       local
  2600.      op: PREFIX_NAME;
  2601.      prefix_freeop: CALL_PREFIX_FREEOP;
  2602.      sp: POSITION;
  2603.       do
  2604.      if a_keyword(as_not) then
  2605.         sp := pos(start_line,start_column);
  2606.         if a_e8 then
  2607.            !CALL_PREFIX_NOT!last_expression.make(sp,last_expression);
  2608.            Result := true;
  2609.         else
  2610.            err_exp(sp,as_not);
  2611.         end;
  2612.      elseif skip1('+') then
  2613.         sp := pos(start_line,start_column);
  2614.         if a_e8 then
  2615.            !CALL_PREFIX_PLUS!last_expression.make(sp,last_expression);
  2616.            Result := true;
  2617.         else
  2618.            err_exp(sp,"+ (prefix)");
  2619.         end;
  2620.      elseif skip1('-') then
  2621.         sp := pos(start_line,start_column);
  2622.         if a_e8 then
  2623.            !CALL_PREFIX_MINUS!last_expression.make(sp,last_expression);
  2624.            Result := true;
  2625.         else
  2626.            err_exp(sp,"- (prefix)");
  2627.         end;
  2628.      elseif a_free_operator then
  2629.         op := tmp_name.to_prefix_name;
  2630.         if a_e8 then
  2631.            !!prefix_freeop.make(last_expression,op);
  2632.            last_expression := prefix_freeop;
  2633.            Result := true;
  2634.         else
  2635.            eh.append("Bad use of prefix operator. ");
  2636.            err_exp(op.start_position,op.to_string);
  2637.         end;
  2638.      else
  2639.         Result := a_e9;
  2640.      end;
  2641.       end;
  2642.  
  2643.    a_e9: BOOLEAN is
  2644.      --++ e9 -> e10 |
  2645.      --++       "old" e10
  2646.      --++
  2647.       do
  2648.      if a_keyword(fz_old) then
  2649.         if not in_ensure then
  2650.            error(pos(start_line,start_column),
  2651.              "Expression %"old%" can be used in ensure clause %
  2652.                        %only (VAOL.1).");
  2653.         end;
  2654.         if a_e10 then
  2655.            !E_OLD!last_expression.make(last_expression);
  2656.            Result := true;
  2657.         else
  2658.            fcp("Expression expected after %"old%".");
  2659.         end;
  2660.      else
  2661.         Result := a_e10;
  2662.      end;
  2663.       end;
  2664.  
  2665.    a_e10: BOOLEAN is
  2666.      --++ e10 -> strip |
  2667.      --++       "(" expression ")" r10 |
  2668.      --++       manifest_constant |
  2669.      --++       precursor_call |
  2670.      --++       "Result" r10 |
  2671.      --++       "Current" r10 |
  2672.      --++       "Void" r10 |
  2673.      --++       local_variable r10 |
  2674.      --++       argument r10 |
  2675.      --++       function_call r10 |
  2676.      --++
  2677.       do
  2678.      if a_strip then
  2679.         Result := true;
  2680.      elseif skip1('(') then
  2681.         Result := true;
  2682.         if a_expression then
  2683.            if skip1(')') then
  2684.           a_r10(false,last_expression,Void,Void);
  2685.            else
  2686.           fcp("')' expected in expression.")
  2687.            end;
  2688.         else
  2689.            fcp("Expression expected.")
  2690.         end;
  2691.      elseif a_manifest_constant then
  2692.         last_expression := last_manifest_constant;
  2693.         Result := true;
  2694.         if skip1('.') then
  2695.            wcp("Added brackets for manifest constant before dot.");
  2696.            a_after_a_dot(false,last_expression);
  2697.         end;
  2698.      elseif a_precursor(false) then
  2699.         Result := true;
  2700.      elseif a_identifier then
  2701.         Result := true;
  2702.         if a_result or else a_current or else a_void or else
  2703.            a_local_variable or else a_argument then
  2704.            a_r10(false,last_expression,Void,Void);
  2705.         else
  2706.            a_function_call;
  2707.         end;
  2708.      end;
  2709.       end;
  2710.  
  2711.    a_external: ROUTINE is
  2712.      --++ external -> "<external-specification>" external_name
  2713.      --++
  2714.       local
  2715.      tag: STRING;
  2716.      l: NATIVE;
  2717.       do
  2718.      if not skip1('%"') then
  2719.         fcp(em18);
  2720.      end;
  2721.      from
  2722.         !!tag.make(24);
  2723.      until
  2724.         cc = '%"'
  2725.      loop
  2726.         if cc = '%%' then
  2727.            next_char;
  2728.         end;
  2729.         tag.extend(cc);
  2730.         next_char;
  2731.      end;
  2732.      if ("SmallEiffel").is_equal(tag) then
  2733.         !NATIVE_SMALL_EIFFEL!l.make(tag);
  2734.      elseif ("compiler built-in").is_equal(tag) then
  2735.         !NATIVE_SMALL_EIFFEL!l.make(tag);
  2736.      elseif ("C_WithCurrent").is_equal(tag) then
  2737.         !NATIVE_WITH_CURRENT!l.make(tag);
  2738.      elseif ("C_InlineWithCurrent").is_equal(tag) then
  2739.         !NATIVE_INLINE_WITH_CURRENT!l.make(tag);
  2740.      elseif ("C_WithoutCurrent").is_equal(tag) then
  2741.         !NATIVE_WITHOUT_CURRENT!l.make(tag);
  2742.      elseif ("C_InlineWithoutCurrent").is_equal(tag) then
  2743.         !NATIVE_INLINE_WITHOUT_CURRENT!l.make(tag);
  2744.      elseif ("CSE").is_equal(tag) then
  2745.         !NATIVE_SMALL_EIFFEL!l.make(tag);
  2746.         wcpefnc("CSE",fz_se);
  2747.      elseif ("CWC").is_equal(tag) then
  2748.         -- To be compatible with Visual Eiffel.
  2749.         !NATIVE_WITH_CURRENT!l.make(tag);
  2750.      elseif ("ICWC").is_equal(tag) then
  2751.         !NATIVE_INLINE_WITH_CURRENT!l.make(tag);
  2752.         wcpefnc("ICWC","C_InlineWithCurrent");
  2753.      elseif ("IC").is_equal(tag) then
  2754.         !NATIVE_INLINE_WITHOUT_CURRENT!l.make(tag);
  2755.         wcpefnc("IC","C_InlineWithoutCurrent");
  2756.      elseif ("JVM_invokestatic").is_equal(tag) then
  2757.         !NATIVE_JVM_INVOKESTATIC!l.make(tag);
  2758.      elseif ("JVM_invokevirtual").is_equal(tag) then
  2759.         !NATIVE_JVM_INVOKEVIRTUAL!l.make(tag);
  2760.      elseif tag.has_prefix("C++") then
  2761.         !NATIVE_C_PLUS_PLUS!l.make(tag);
  2762.      elseif tag.has_prefix("C") then
  2763.         !NATIVE_WITHOUT_CURRENT!l.make(tag);
  2764.      else
  2765.         fcp("Unkown external specification.");
  2766.      end;
  2767.      if not skip1('%"') then
  2768.         fcp(em18);
  2769.      end;
  2770.      Result := tmp_feature.to_external_routine(l,a_alias);
  2771.       end;
  2772.  
  2773.    a_alias: STRING is
  2774.      --++ external_name -> ["alias" manifest_string]
  2775.      --++
  2776.       do
  2777.      if a_keyword(fz_alias) then
  2778.         if not skip1('%"') then
  2779.            fcp(em19);
  2780.         end;
  2781.         from
  2782.            !!Result.make(24);
  2783.         until
  2784.            cc = '%"'
  2785.         loop
  2786.            Result.extend(cc);
  2787.            next_char;
  2788.         end;
  2789.         if not skip1('%"') then
  2790.            fcp(em19);
  2791.         end;
  2792.      end;
  2793.       end;
  2794.  
  2795.    a_feature_name_list: BOOLEAN is
  2796.      --++ feature_name_list -> {feature_name "," ...}
  2797.      --++
  2798.      --
  2799.      -- Gives true when list is not empty.
  2800.       local
  2801.      state: INTEGER;
  2802.      -- state 0 : nothing read.
  2803.      -- state 1 : feature name read.
  2804.      -- state 2 : separator read.
  2805.      -- state 3 : end.
  2806.       do
  2807.      from
  2808.         last_feature_name_list := Void;
  2809.      until
  2810.         state >= 3
  2811.      loop
  2812.         inspect
  2813.            state
  2814.         when 0 then
  2815.            if a_feature_name then
  2816.           !!last_feature_name_list.make_1(last_feature_name);
  2817.           Result := true;
  2818.           state := 1;
  2819.            elseif cc = ',' then
  2820.           wcp(em7);
  2821.           ok := skip1(',');
  2822.            else
  2823.           state := 3
  2824.            end;
  2825.         when 1 then
  2826.            if cc = ',' then
  2827.           ok := skip1(',');
  2828.           state := 2;
  2829.            elseif a_feature_name then
  2830.           warning(last_feature_name.start_position,em5);
  2831.           last_feature_name_list.add_last(last_feature_name);
  2832.            else
  2833.           state := 3;
  2834.            end;
  2835.         when 2 then
  2836.            if a_feature_name then
  2837.           last_feature_name_list.add_last(last_feature_name);
  2838.           state := 1;
  2839.            elseif cc = ',' then
  2840.           wcp(em12);
  2841.           ok := skip1(',');
  2842.            else
  2843.           ecp(em2);
  2844.           state := 3;
  2845.            end;
  2846.         end;
  2847.      end;
  2848.       end;
  2849.  
  2850.    a_feature_name: BOOLEAN is
  2851.      --++ feature_name -> prefix |
  2852.      --++                 infix |
  2853.      --++                 simple_feature_name
  2854.      --++
  2855.       do
  2856.      if a_prefix then
  2857.         last_feature_name := last_prefix;
  2858.         Result := true;
  2859.      elseif a_infix then
  2860.         last_feature_name := last_infix;
  2861.         Result := true;
  2862.      elseif a_identifier then
  2863.         last_feature_name := tmp_name.to_simple_feature_name;
  2864.         Result := true;
  2865.      end;
  2866.       end;
  2867.  
  2868.    a_feature_clause is
  2869.      --++ feature_clause -> [clients] [comment] feature_declaration_list
  2870.      --++
  2871.       local
  2872.      feature_clause: FEATURE_CLAUSE;
  2873.      clients: CLIENT_LIST;
  2874.      comment: COMMENT;
  2875.       do
  2876.      from
  2877.         clients := a_clients;
  2878.         comment := get_comments;
  2879.         faof.clear;
  2880.      until
  2881.         not a_feature_declaration
  2882.      loop
  2883.         ok := skip1(';');
  2884.         if last_feature_declaration /= Void then
  2885.            faof.add_last(last_feature_declaration);
  2886.            last_feature_declaration.set_header_comment(get_comments);
  2887.         end;
  2888.      end;
  2889.      if not faof.is_empty then
  2890.         !!feature_clause.make(clients,comment,faof.twin);
  2891.         last_base_class.add_feature_clause(feature_clause);
  2892.      elseif comment /= Void then
  2893.         !!feature_clause.make(clients,comment,Void);
  2894.         last_base_class.add_feature_clause(feature_clause);
  2895.      end;
  2896.      last_keyword := Void;
  2897.       end;
  2898.  
  2899.    a_feature_declaration: BOOLEAN is
  2900.      --++ feature_declaration -> {["frozen"] feature_name "," ...}+
  2901.      --++                        formal_arg_list
  2902.      --++                        [":" type]
  2903.      --++                        ["is" "unique" |
  2904.      --++                         "is" manifest_constant |
  2905.      --++                         "is" routine]
  2906.      --++
  2907.       do
  2908.      from
  2909.         tmp_feature.initialize;
  2910.         if a_keyword(fz_frozen) then
  2911.            if a_feature_name then
  2912.           Result := true;
  2913.           to_frozen_feature_name;
  2914.           tmp_feature.add_synonym(last_feature_name);
  2915.            else
  2916.           fcp(em2);
  2917.            end;
  2918.         elseif a_feature_name then
  2919.            Result := true;
  2920.            tmp_feature.add_synonym(last_feature_name);
  2921.         end;
  2922.      until
  2923.         not skip1(',')
  2924.      loop
  2925.         if a_keyword(fz_frozen) then
  2926.            if a_feature_name then
  2927.           to_frozen_feature_name;
  2928.           tmp_feature.add_synonym(last_feature_name);
  2929.            else
  2930.           fcp("Frozen feature name synonym expected.");
  2931.            end;
  2932.         elseif a_feature_name then
  2933.            tmp_feature.add_synonym(last_feature_name);
  2934.         else
  2935.            ecp("Synonym feature name expected.");
  2936.         end;
  2937.      end;
  2938.      if Result then
  2939.         a_formal_arg_list;
  2940.         if skip1(':') then
  2941.            if a_type then
  2942.           inside_function := true;
  2943.           tmp_feature.set_type(last_type);
  2944.            else
  2945.           fcp(em16);
  2946.            end;
  2947.         else
  2948.            inside_function := false;
  2949.         end;
  2950.         if a_keyword(fz_is) then
  2951.            if a_keyword(fz_unique) then
  2952.           last_feature_declaration := tmp_feature.to_cst_att_unique;
  2953.            elseif a_boolean_constant then
  2954.           last_feature_declaration :=
  2955.              tmp_feature.to_cst_att_boolean(last_boolean_constant);
  2956.            elseif a_character_constant then
  2957.           last_feature_declaration :=
  2958.              tmp_feature.to_cst_att_character(last_character_constant);
  2959.            elseif a_manifest_string then
  2960.           last_feature_declaration :=
  2961.              tmp_feature.to_cst_att_string(last_manifest_string);
  2962.            elseif a_bit_constant then
  2963.           last_feature_declaration :=
  2964.              tmp_feature.to_cst_att_bit(last_bit_constant);
  2965.            elseif a_real_constant then
  2966.           last_feature_declaration :=
  2967.              tmp_feature.to_cst_att_real(last_real_constant);
  2968.            elseif a_integer_constant then
  2969.           last_feature_declaration :=
  2970.              tmp_feature.to_cst_att_integer(last_integer_constant);
  2971.            else
  2972.           last_feature_declaration := a_routine;
  2973.            end;
  2974.         else
  2975.            last_feature_declaration := tmp_feature.to_writable_attribute;
  2976.         end;
  2977.         inside_function := false;
  2978.         inside_once_function := false;
  2979.         arguments := Void;
  2980.      end;
  2981.       end;
  2982.  
  2983.    a_formal_generic_list is
  2984.      --++ formal_generic_list -> ["[" {formal_generic "," ...} "]"]
  2985.      --++ formal_generic -> base_class_name ["->" class_type]
  2986.      --++
  2987.       local
  2988.      l, c: INTEGER;
  2989.      name: CLASS_NAME;
  2990.      constraint: TYPE;
  2991.      fga: FORMAL_GENERIC_ARG;
  2992.      list: ARRAY[FORMAL_GENERIC_ARG];
  2993.      state: INTEGER;
  2994.      -- state 0 : waiting for "[".
  2995.      -- state 1 : waiting for a base class `name'.
  2996.      -- state 2 : waiting for "->" or "," or "]".
  2997.      -- state 3 : waiting for "," or "]".
  2998.      -- state 4 : waiting for a `constraint' type.
  2999.      -- state 5 : end.
  3000.      -- state 6 : error.
  3001.       do
  3002.      from
  3003.         formal_generic_list := Void;
  3004.      until
  3005.         state > 4
  3006.      loop
  3007.         inspect
  3008.            state
  3009.         when 0 then
  3010.            if skip1('%(') then
  3011.           l := start_line;
  3012.           c := start_column;
  3013.           state := 1;
  3014.            else
  3015.           state := 5;
  3016.            end;
  3017.         when 1 then
  3018.            if a_base_class_name then
  3019.           name := last_class_name;
  3020.           state := 2;
  3021.            else
  3022.           state := 6;
  3023.            end;
  3024.         when 2 then
  3025.            if skip2('-','>') then
  3026.           state := 4;
  3027.            elseif cc = ',' or else cc = ']' then
  3028.           !!fga.make(name,constraint);
  3029.           name := Void;
  3030.           constraint := Void;
  3031.           if list = Void then
  3032.              !!list.with_capacity(2,1);
  3033.           end;
  3034.           list.add_last(fga);
  3035.           fga := Void;
  3036.           if skip1(',') then
  3037.              state := 1;
  3038.           else
  3039.              ok := skip1('%)');
  3040.              state := 5;
  3041.           end;
  3042.            else
  3043.           state := 6;
  3044.            end;
  3045.         when 3 then
  3046.            if cc = ',' or else cc = ']' then
  3047.           !!fga.make(name,constraint);
  3048.           name := Void;
  3049.           constraint := Void;
  3050.           if list = Void then
  3051.              !!list.with_capacity(2,1);
  3052.           end;
  3053.           list.add_last(fga);
  3054.           fga := Void;
  3055.           if skip1(',') then
  3056.              state := 1;
  3057.           else
  3058.              ok := skip1('%)');
  3059.              state := 5;
  3060.           end;
  3061.            else
  3062.           state := 6;
  3063.            end;
  3064.         else -- state = 4
  3065.            if a_class_type then
  3066.           constraint := last_class_type;
  3067.           state := 3;
  3068.            else
  3069.           fcp("Constraint Class name expected.");
  3070.           state := 6;
  3071.            end;
  3072.         end;
  3073.      end;
  3074.      if state = 6 then
  3075.         check
  3076.            nb_errors > 0;
  3077.         end;
  3078.      elseif l > 0 and then list = Void then
  3079.         warning(pos(l,c),"Empty formal generic list (deleted).");
  3080.      elseif l > 0 then
  3081.         check
  3082.            not list.is_empty;
  3083.         end;
  3084.         !!formal_generic_list.make(pos(l,c),list);
  3085.         last_base_class.set_formal_generic_list(formal_generic_list);
  3086.      end;
  3087.       end;
  3088.  
  3089.    a_function_call is
  3090.      --++ function_call -> [actuals] r10 |
  3091.      --++                   ^
  3092.      --++
  3093.       local
  3094.      sfn: SIMPLE_FEATURE_NAME;
  3095.      implicit_current: IMPLICIT_CURRENT;
  3096.       do
  3097.      sfn := tmp_name.to_simple_feature_name;
  3098.      !!implicit_current.make(sfn.start_position);
  3099.      a_r10(false,implicit_current,sfn,a_actuals);
  3100.       end;
  3101.  
  3102.    a_index_clause: BOOLEAN is
  3103.      --++ index_clause -> [identifier ":"] {index_value "," ...}+
  3104.      --++
  3105.       local
  3106.      index_clause: INDEX_CLAUSE;
  3107.       do
  3108.      if a_identifier then
  3109.         Result := true;
  3110.         if skip1(':') then
  3111.            !!index_clause.with_tag(tmp_name.aliased_string);
  3112.            if a_index_value then
  3113.           index_clause.add_last(last_index_value);
  3114.            else
  3115.           fcp(em3);
  3116.            end;
  3117.         else
  3118.            !!index_clause.without_tag(tmp_name.to_simple_feature_name);
  3119.         end;
  3120.      elseif a_manifest_constant then
  3121.         Result := true;
  3122.         !!index_clause.without_tag(last_manifest_constant);
  3123.      end;
  3124.      if Result then
  3125.         from
  3126.         until
  3127.            not skip1(',')
  3128.         loop
  3129.            if a_index_value then
  3130.           index_clause.add_last(last_index_value);
  3131.            else
  3132.           fcp(em3);
  3133.            end;
  3134.         end;
  3135.         last_base_class.add_index_clause(index_clause);
  3136.      end;
  3137.       end;
  3138.  
  3139.    a_index_value: BOOLEAN is
  3140.      --++ index_value -> identifier | manifest_constant
  3141.      --++
  3142.       do
  3143.      if a_identifier then
  3144.         last_index_value := tmp_name.to_simple_feature_name;
  3145.         Result := true;
  3146.      elseif a_manifest_constant then
  3147.         last_index_value := last_manifest_constant;
  3148.         Result := true;
  3149.      end;
  3150.       end;
  3151.  
  3152.    a_indexing is
  3153.      --++ indexing -> "indexing" {index_clause ";" ...}
  3154.      --++
  3155.       do
  3156.      if a_keyword(fz_indexing) then
  3157.         from
  3158.         until
  3159.            not a_index_clause
  3160.         loop
  3161.            ok := skip1(';');
  3162.         end;
  3163.      end;
  3164.       end;
  3165.  
  3166.    a_infix: BOOLEAN is
  3167.      --++ infix -> "infix" "%"" binary "%""
  3168.      --++          "infix" "%"" free_operator "%""
  3169.      --++
  3170.       local
  3171.      sp: POSITION;
  3172.       do
  3173.      if a_keyword(fz_infix) then
  3174.         Result := true;
  3175.         sp := pos(start_line,start_column);
  3176.         if cc = '%"' then
  3177.            next_char;
  3178.         else
  3179.            wcp("Character '%%%"' inserted after %"infix%".");
  3180.         end;
  3181.         if a_binary(sp) then
  3182.            last_infix := last_binary;
  3183.         elseif a_free_operator then
  3184.            last_infix := tmp_name.to_infix_name(sp);
  3185.         else
  3186.            fcp("Infix operator name expected.");
  3187.         end;
  3188.         if not skip1('%"') then
  3189.            wcp("Character '%%%"' inserted.");
  3190.         end;
  3191.      end;
  3192.       end;
  3193.  
  3194.    a_inspect: BOOLEAN is
  3195.      --++ inspect -> "inspect" expression
  3196.      --++            {when_part ...}
  3197.      --++            ["else" compound]
  3198.      --++            "end"
  3199.      --++
  3200.       local
  3201.      sp, spec: POSITION;
  3202.      i: E_INSPECT;
  3203.      ec: COMPOUND;
  3204.       do
  3205.      if a_keyword(fz_inspect) then
  3206.         Result := true;
  3207.         sp := pos(start_line,start_column);
  3208.         if a_expression then
  3209.            last_expression := last_expression.add_comment(get_comments);
  3210.         else
  3211.            fcp("Expression expected (%"inspect ... %").");
  3212.         end;
  3213.         from
  3214.            !!i.make(sp,last_expression);
  3215.         until
  3216.            not a_when_part(i)
  3217.         loop
  3218.         end;
  3219.         if a_keyword(fz_else) then
  3220.            spec := pos(start_line,start_column);
  3221.            ec := a_compound2("else of inspect",fz_end);
  3222.            i.set_else_compound(spec,ec);
  3223.         elseif not a_keyword(fz_end) then
  3224.            wcp("Added %"end%" for inspect instruction.");
  3225.         end;
  3226.         last_instruction := i;
  3227.      end;
  3228.       end;
  3229.  
  3230.    a_instruction: BOOLEAN is
  3231.      --++ instruction -> check | debug | conditionnal | retry |
  3232.      --++                inspect | loop | creation | assignment_or_call
  3233.      --++
  3234.       do
  3235.      Result := true;
  3236.      if a_check then
  3237.      elseif a_debug then
  3238.      elseif a_conditional then
  3239.      elseif a_retry then
  3240.      elseif a_inspect then
  3241.      elseif a_loop then
  3242.      elseif a_create_instruction then
  3243.      elseif a_assignment_or_call then
  3244.      elseif a_creation then
  3245.      else
  3246.         Result := false;
  3247.      end;
  3248.       end;
  3249.  
  3250.    a_integer_constant: BOOLEAN is
  3251.      --++ integer_constant -> ["+" | "-"] integer
  3252.      --++
  3253.       do
  3254.      if skip1('+') then
  3255.         if a_integer then
  3256.            Result := true;
  3257.         else
  3258.            fcp(fz_iinaiv);
  3259.         end;
  3260.      elseif skip1('-') then
  3261.         if a_integer then
  3262.            last_integer_constant.unary_minus;
  3263.            Result := true;
  3264.         else
  3265.            fcp(fz_iinaiv);
  3266.         end;
  3267.      else
  3268.         Result := a_integer;
  3269.      end;
  3270.       end;
  3271.  
  3272.    a_loop: BOOLEAN is
  3273.      --++ loop -> "from" compound
  3274.      --++         ["invariant"] assertion
  3275.      --++         ["variant" [identifier ":"] expression]
  3276.      --++         "until" expression
  3277.      --++         "loop" compound
  3278.      --++         "end"
  3279.      --++
  3280.       local
  3281.      l1, c1, l2, c2: INTEGER;
  3282.      e_loop: E_LOOP;
  3283.      i: COMPOUND;
  3284.      ic: LOOP_INVARIANT;
  3285.      vc: LOOP_VARIANT;
  3286.      ue: EXPRESSION;
  3287.      lb: COMPOUND;
  3288.      hc: COMMENT;
  3289.      al: ARRAY[ASSERTION];
  3290.       do
  3291.      if a_keyword(fz_from) then
  3292.         Result := true;
  3293.         l1 := start_line;
  3294.         c1 := start_column;
  3295.         i := a_compound1;
  3296.         if a_keyword(fz_invariant) then
  3297.            l2 := start_line;
  3298.            c2 := start_column;
  3299.            hc := get_comments;
  3300.            al := a_assertion;
  3301.            if hc /= Void or else al /= Void then
  3302.           !!ic.make(pos(l2,c2),hc,al);
  3303.            end;
  3304.         end;
  3305.         if a_keyword(fz_variant) then
  3306.            if a_tag_mark and then a_expression then
  3307.           !LOOP_VARIANT_2!vc.make(last_tag_mark,last_expression,
  3308.                       get_comments);
  3309.            elseif a_expression then
  3310.           !LOOP_VARIANT_1!vc.make(last_expression,get_comments);
  3311.            else
  3312.           wcp("Variant (INTEGER) Expression Expected.");
  3313.            end;
  3314.         end;
  3315.         if a_keyword(fz_until) then
  3316.            if a_expression then
  3317.           ue := last_expression.add_comment(get_comments);
  3318.            else
  3319.           fcp("Boolean expression expected (until).");
  3320.           ue := last_expression;
  3321.            end;
  3322.         else
  3323.            fcp("Keyword %"until%" expected (in a loop).");
  3324.            ue := last_expression;
  3325.         end;
  3326.         if cc = ';' then
  3327.            wcp(fz_desc);
  3328.            ok := skip1(';');
  3329.         end;
  3330.         if not a_keyword(fz_loop) then
  3331.            wcp("Keyword %"loop%" expected (in a loop).");
  3332.         end;
  3333.         lb := a_compound2("loop body",fz_end);
  3334.         !!e_loop.make(pos(l1,c1),i,ic,vc,ue,lb);
  3335.         last_instruction := e_loop;
  3336.      end;
  3337.       end;
  3338.  
  3339.    a_manifest_constant: BOOLEAN is
  3340.      --++ manifest_constant -> boolean_constant | character_constant |
  3341.      --++                      real_constant | integer_constant |
  3342.      --++                      manifest_string | bit_constant
  3343.      --++
  3344.       do
  3345.      if a_boolean_constant then
  3346.         last_manifest_constant := last_boolean_constant;
  3347.         Result := true;
  3348.      elseif a_character_constant then
  3349.         last_manifest_constant := last_character_constant;
  3350.         Result := true;
  3351.      elseif a_manifest_string then
  3352.         last_manifest_constant := last_manifest_string;
  3353.         Result := true;
  3354.      elseif a_bit_constant then
  3355.         last_manifest_constant := last_bit_constant;
  3356.         Result := true;
  3357.      elseif a_real_constant then
  3358.         last_manifest_constant := last_real_constant;
  3359.         Result := true;
  3360.      elseif a_integer_constant then
  3361.         last_manifest_constant := last_integer_constant;
  3362.         Result := true;
  3363.      end;
  3364.       end;
  3365.  
  3366.    a_new_export_list is
  3367.      --++ new_export_list -> ["export" {new_export_item ";" ...}]
  3368.      --++ new_export_item -> clients "all" |
  3369.      --++                    clients feature_list
  3370.      --++
  3371.       local
  3372.      export_list: EXPORT_LIST;
  3373.      sp: POSITION;
  3374.      clients: CLIENT_LIST;
  3375.      items: ARRAY[EXPORT_ITEM];
  3376.      new_export_item: EXPORT_ITEM;
  3377.      state: INTEGER;
  3378.      -- state 0 : waiting for a `clients'.
  3379.      -- state 1 : `clients' read.
  3380.      -- state 2 : waiting ";" before next one.
  3381.      -- state 3 : error.
  3382.      -- state 4 : end.
  3383.      --
  3384.       do
  3385.      if a_keyword(fz_export) then
  3386.         from
  3387.            sp := pos(start_line,start_column);
  3388.         until
  3389.            state > 3
  3390.         loop
  3391.            inspect
  3392.           state
  3393.            when 0 then
  3394.           if cc = '{' then
  3395.              clients := a_clients;
  3396.              state := 1;
  3397.           elseif cc = ';' then
  3398.              wcp(fz_desc);
  3399.              ok := skip1(';');
  3400.           else
  3401.              if items /= Void then
  3402.             !!export_list.make(sp,items);
  3403.             last_parent.set_export(export_list);
  3404.              end;
  3405.              state := 4;
  3406.           end;
  3407.            when 1 then
  3408.           if a_keyword(fz_all) then
  3409.              !!new_export_item.make_all(clients);
  3410.              if items = Void then
  3411.             !!items.with_capacity(2,1);
  3412.              end;
  3413.              items.add_last(new_export_item);
  3414.              state := 2;
  3415.           else
  3416.              if a_feature_name_list then
  3417.             !!new_export_item.make(clients,last_feature_name_list);
  3418.             if items = Void then
  3419.                !!items.with_capacity(2,1);
  3420.             end;
  3421.             items.add_last(new_export_item);
  3422.             state := 2;
  3423.              else
  3424.             state := 3;
  3425.              end;
  3426.           end;
  3427.            when 2 then
  3428.           if skip1(';') then
  3429.              state := 0;
  3430.           elseif cc = '{' then
  3431.              wcp(em6);
  3432.              state := 0;
  3433.           else
  3434.              if items /= Void then
  3435.             !!export_list.make(sp,items);
  3436.             last_parent.set_export(export_list);
  3437.              end;
  3438.              state := 4;
  3439.           end;
  3440.            else -- state = 3
  3441.           fcp(em11);
  3442.           state := 4;
  3443.            end;
  3444.         end;
  3445.      end;
  3446.       end;
  3447.  
  3448.    a_parent_list(sp: POSITION; hc: COMMENT) is
  3449.      --++ parent_list -> {parent ";" ...}
  3450.      --++
  3451.       local
  3452.      list: ARRAY[PARENT];
  3453.       do
  3454.      from
  3455.      until
  3456.         not a_parent
  3457.      loop
  3458.         if list = Void then
  3459.            !!list.with_capacity(4,1);
  3460.         end;
  3461.         list.add_last(last_parent);
  3462.         ok := skip1(';');
  3463.         last_parent.set_comment(get_comments);
  3464.      end;
  3465.      if hc /= Void or else list /= Void then
  3466.         if list = Void then
  3467.            if last_base_class.heading_comment2 = Void then
  3468.           last_base_class.set_heading_comment2(hc);
  3469.            else
  3470.           last_base_class.heading_comment2.append(hc);
  3471.            end;
  3472.         else
  3473.            last_base_class.set_parent_list(sp,hc,list);
  3474.         end;
  3475.      end;
  3476.       end;
  3477.  
  3478.    a_parent: BOOLEAN is
  3479.      --++ parent -> class_type
  3480.      --++           ["rename" rename_list]
  3481.      --++           new_export_list
  3482.      --++           ["undefine" feature_name_list]
  3483.      --++           ["redefine" feature_name_list]
  3484.      --++           ["select" feature_name_list]
  3485.      --++           ["end"]
  3486.      --++
  3487.       do
  3488.      if a_class_type then
  3489.         Result := true;
  3490.         !!last_parent.make(last_class_type);
  3491.         if a_keyword(fz_rename) then
  3492.            a_rename_list;
  3493.            if cc = ';' then
  3494.           wcp("Unexpected %";%" to end rename list.");
  3495.           ok := skip1(';');
  3496.            end;
  3497.         end;
  3498.         a_new_export_list;
  3499.         if a_keyword(fz_undefine) then
  3500.            if a_feature_name_list then
  3501.           last_parent.set_undefine(last_feature_name_list)
  3502.            end;
  3503.         end;
  3504.         if a_keyword(fz_redefine) then
  3505.            if a_feature_name_list then
  3506.           last_parent.set_redefine(last_feature_name_list)
  3507.            end;
  3508.         end;
  3509.         if a_keyword(fz_select) then
  3510.            if a_feature_name_list then
  3511.           last_parent.set_select(last_feature_name_list);
  3512.            end;
  3513.         end;
  3514.         if a_keyword(fz_rename) or else
  3515.            a_keyword(fz_export) or else
  3516.            a_keyword(fz_undefine) or else
  3517.            a_keyword(fz_redefine) or else
  3518.            a_keyword(fz_select) then
  3519.            eh.add_position(pos(start_line,start_column));
  3520.            fatal_error("Inheritance option not at a good place. %
  3521.                %The good order is: %"rename... export... %
  3522.                         %undefine... redefine... select...%".");
  3523.                         end;
  3524.                         ok := a_keyword(fz_end);
  3525.                          end;
  3526.                       end;
  3527.  
  3528.                       a_prefix: BOOLEAN is
  3529.      --++ prefix -> "prefix" "%"" unary "%""
  3530.      --++           "prefix" "%"" free_operator "%""
  3531.      --++
  3532.       do
  3533.      if a_keyword(fz_prefix) then
  3534.         Result := true;
  3535.         if cc = '%"' then
  3536.            next_char;
  3537.         else
  3538.            wcp("Character '%%%"' inserted after %"prefix%".");
  3539.         end;
  3540.         if a_unary then
  3541.         elseif a_free_operator then
  3542.            last_prefix := tmp_name.to_prefix_name;
  3543.         else
  3544.            fcp("Prefix operator name expected.");
  3545.         end;
  3546.         if not skip1('%"') then
  3547.            wcp("Character '%%%"' inserted.");
  3548.         end;
  3549.      end;
  3550.       end;
  3551.  
  3552.    a_precursor(do_instruction: BOOLEAN): BOOLEAN is
  3553.      --++ precursor -> ["{" class_name "}"] "Precursor" [actuals] |
  3554.      --++              ^
  3555.      --++
  3556.       local
  3557.      l, c: INTEGER;
  3558.      parent: CLASS_NAME;
  3559.      args: EFFECTIVE_ARG_LIST;
  3560.       do
  3561.      if skip1('{') then
  3562.         Result := true;
  3563.         l := start_line;
  3564.         c := start_column;
  3565.         if skip1('{') then
  3566.            warning(pos(start_line,start_column),
  3567.                "One single opening '{' is correct too here.");
  3568.         end;
  3569.         if a_base_class_name then
  3570.            parent := last_class_name;
  3571.         end;
  3572.         if not skip1('}')  then
  3573.            fcp("Closing '}' expected to end Precursor's parent qualification.");
  3574.         end;
  3575.         if skip1('}') then
  3576.            warning(pos(start_line,start_column),
  3577.                "One single closing '}' is correct too here.");
  3578.         end;
  3579.      end;
  3580.      if a_keyword(as_precursor) then
  3581.         Result := true;
  3582.         if l = 0 then
  3583.            l := start_line;
  3584.            c := start_column;
  3585.         end;
  3586.         args := a_actuals;
  3587.      elseif l > 0 then
  3588.         fcp("Precursor keyword expected here.");
  3589.      end;
  3590.      if Result then
  3591.         if skip1('.') then
  3592.            !E_PRECURSOR_FUNCTION!last_expression.make(pos(l,c),parent,args);
  3593.            a_after_a_dot(do_instruction,last_expression);
  3594.         elseif do_instruction then
  3595.            !E_PRECURSOR_PROCEDURE!last_instruction.make(pos(l,c),parent,args);
  3596.         else
  3597.            !E_PRECURSOR_FUNCTION!last_expression.make(pos(l,c),parent,args);
  3598.         end;
  3599.      end;
  3600.       end;
  3601.  
  3602.    a_procedure_call is
  3603.      --++ procedure_call -> [actuals] r10 |
  3604.      --++                   ^
  3605.      --++
  3606.       local
  3607.      sfn: SIMPLE_FEATURE_NAME;
  3608.      implicit_current: IMPLICIT_CURRENT;
  3609.       do
  3610.      sfn := tmp_name.to_simple_feature_name;
  3611.      !!implicit_current.make(sfn.start_position);
  3612.      a_r10(true,implicit_current,sfn,a_actuals);
  3613.       end;
  3614.  
  3615.    a_real_constant: BOOLEAN is
  3616.      --++ real_constant -> ["+" | "-"] real
  3617.      --++
  3618.       local
  3619.      l, c: INTEGER;
  3620.       do
  3621.      l := line;
  3622.      c := column;
  3623.      if skip1('+') then
  3624.         if a_real then
  3625.            Result := true;
  3626.         else
  3627.            go_back_at(l,c);
  3628.         end;
  3629.      elseif skip1('-') then
  3630.         if a_real then
  3631.            last_real_constant.unary_minus;
  3632.            Result := true;
  3633.         else
  3634.            go_back_at(l,c);
  3635.         end;
  3636.      elseif a_real then
  3637.         Result := true;
  3638.      end;
  3639.       end;
  3640.  
  3641.    a_rename_list is
  3642.      --++ rename_list -> {rename_pair "," ...}
  3643.      --++
  3644.       do
  3645.      from
  3646.      until
  3647.         not a_rename_pair
  3648.      loop
  3649.         ok := skip1(',');
  3650.      end;
  3651.       end;
  3652.  
  3653.    a_rename_pair: BOOLEAN is
  3654.      --++ rename_pair -> identifier "as" identifier
  3655.      --++
  3656.       local
  3657.      name1: FEATURE_NAME;
  3658.      rename_pair: RENAME_PAIR;
  3659.      l, c: INTEGER;
  3660.       do
  3661.      l := line;
  3662.      c := column;
  3663.      if a_feature_name then
  3664.         name1 := last_feature_name;
  3665.         if a_keyword(fz_as) then
  3666.            if a_feature_name then
  3667.           Result := true;
  3668.           !!rename_pair.make(name1,last_feature_name);
  3669.           last_parent.add_rename(rename_pair);
  3670.            else
  3671.           fcp("Second identifier of a %"rename%" pair expected.");
  3672.            end;
  3673.         else
  3674.            go_back_at(l,c);
  3675.         end;
  3676.      end;
  3677.       end;
  3678.  
  3679.    a_routine: ROUTINE is
  3680.      --++ routine -> ["obsolete" manifest_string]
  3681.      --++            ["require" ["else"] assertion]
  3682.      --++            ["local" entity_declaration_list]
  3683.      --++            routine_body
  3684.      --++            ["ensure" ["then"] assertion]
  3685.      --++            ["rescue" compound]
  3686.      --++            "end"
  3687.      --++
  3688.       local
  3689.      sp: POSITION;
  3690.      hc: COMMENT;
  3691.      al: ARRAY[ASSERTION];
  3692.      ea: E_ENSURE;
  3693.  
  3694.       do
  3695.      if a_keyword(fz_obsolete) then
  3696.         if a_manifest_string then
  3697.            tmp_feature.set_obsolete_mark(last_manifest_string);
  3698.         else
  3699.            fcp("Obsolete manifest string expected.");
  3700.         end;
  3701.      end;
  3702.      tmp_feature.set_header_comment(get_comments);
  3703.      if a_keyword(fz_require) then
  3704.         sp := pos(start_line,start_column);
  3705.         if a_keyword(fz_else) then
  3706.            hc := get_comments;
  3707.            tmp_feature.set_require_else(sp,hc,a_assertion);
  3708.         else
  3709.            hc := get_comments;
  3710.            tmp_feature.set_require(sp,hc,a_assertion);
  3711.         end;
  3712.      end;
  3713.      if a_keyword(fz_local) then
  3714.         a_local_var_list;
  3715.      end;
  3716.      Result := a_routine_body;
  3717.      if a_keyword(fz_ensure) then
  3718.         sp := pos(start_line,start_column);
  3719.         in_ensure := true;
  3720.         if a_keyword(fz_then) then
  3721.            hc := get_comments;
  3722.            al := a_assertion;
  3723.            if hc /= Void or else al /= Void then
  3724.           !!ea.make(sp,hc,al);
  3725.           ea.set_ensure_then;
  3726.            end;
  3727.            Result.set_ensure_assertion(ea);
  3728.         else
  3729.            hc := get_comments;
  3730.            al := a_assertion;
  3731.            if hc /= Void or else al /= Void then
  3732.           !!ea.make(sp,hc,al);
  3733.            end;
  3734.            Result.set_ensure_assertion(ea);
  3735.         end;
  3736.         in_ensure := false;
  3737.      end;
  3738.      if a_keyword(fz_rescue) then
  3739.         in_rescue := true;
  3740.         Result.set_rescue_compound(a_compound2(fz_rescue,fz_end));
  3741.         in_rescue := false;
  3742.      elseif not a_keyword(fz_end) then
  3743.         wcp("A routine must be ended with %"end%".");
  3744.      end;
  3745.      local_vars := Void;
  3746.       end;
  3747.  
  3748.    a_routine_body: ROUTINE is
  3749.      --++ routine_body -> "deferred" |
  3750.      --++                 "external" external |
  3751.      --++                 "do" compound |
  3752.      --++                 "once" compound
  3753.      --++
  3754.       do
  3755.      if a_keyword(fz_deferred) then
  3756.         last_base_class.set_is_deferred;
  3757.         Result := tmp_feature.to_deferred_routine;
  3758.      elseif a_keyword(fz_external) then
  3759.         Result := a_external;
  3760.      elseif a_keyword(fz_do) then
  3761.         tmp_feature.set_routine_body(a_compound1);
  3762.         Result := tmp_feature.to_procedure_or_function;
  3763.      elseif a_keyword(fz_once) then
  3764.         inside_once_function := true;
  3765.         tmp_feature.set_routine_body(a_compound1);
  3766.         Result := tmp_feature.to_once_routine;
  3767.      else
  3768.         fcp("Routine body expected.");
  3769.      end;
  3770.       end;
  3771.  
  3772.    a_r1(left_part: like last_expression) is
  3773.      --++ r1 -> "implies" e1 r1 |
  3774.      --++       ^
  3775.      --++
  3776.       local
  3777.      infix_implies: CALL_INFIX_IMPLIES;
  3778.      sp: POSITION;
  3779.       do
  3780.      if a_keyword(as_implies) then
  3781.         sp := pos(start_line,start_column);
  3782.         if a_e1 then
  3783.            !!infix_implies.make(left_part,sp,last_expression);
  3784.            a_r1(infix_implies);
  3785.         else
  3786.            error(sp,"Expression expected after 'implies'.");
  3787.         end;
  3788.      else
  3789.         last_expression := left_part;
  3790.      end;
  3791.       end;
  3792.  
  3793.    a_r2(left_part: like last_expression) is
  3794.      --++ r2 -> "or else" e2 r2 |
  3795.      --++       "or" e2 r2 |
  3796.      --++       "xor" e2 r2 |
  3797.      --++       ^
  3798.      --++
  3799.       local
  3800.      infix_or_else: CALL_INFIX_OR_ELSE;
  3801.      infix_or: CALL_INFIX_OR;
  3802.      infix_xor: CALL_INFIX_XOR;
  3803.      sp: POSITION;
  3804.       do
  3805.      if a_keyword(as_or) then
  3806.         sp := pos(start_line,start_column);
  3807.         if a_keyword(fz_else) then
  3808.            if a_e2 then
  3809.           !!infix_or_else.make(left_part,sp,last_expression);
  3810.           a_r2(infix_or_else);
  3811.            else
  3812.           err_exp(sp,as_or_else);
  3813.            end;
  3814.         else
  3815.            if a_e2 then
  3816.           !!infix_or.make(left_part,sp,last_expression);
  3817.           a_r2(infix_or);
  3818.            else
  3819.           err_exp(sp,as_or);
  3820.            end;
  3821.         end;
  3822.      elseif a_keyword(as_xor) then
  3823.         sp := pos(start_line,start_column);
  3824.         if a_e2 then
  3825.            !!infix_xor.make(left_part,sp,last_expression);
  3826.            a_r2(infix_xor);
  3827.         else
  3828.            err_exp(sp,as_xor);
  3829.         end;
  3830.      else
  3831.         last_expression := left_part;
  3832.      end;
  3833.       end;
  3834.  
  3835.    a_r3(left_part: like last_expression) is
  3836.      --++ r3 -> "and then" e3 r3 |
  3837.      --++       "and" e3 r3 |
  3838.      --++       ^
  3839.      --++
  3840.       local
  3841.      infix_and_then: CALL_INFIX_AND_THEN;
  3842.      infix_and: CALL_INFIX_AND;
  3843.      sp: POSITION;
  3844.       do
  3845.      if a_keyword(as_and) then
  3846.         sp := pos(start_line,start_column);
  3847.         if a_keyword(fz_then) then
  3848.            if a_e3 then
  3849.           !!infix_and_then.make(left_part,sp,last_expression);
  3850.           a_r3(infix_and_then);
  3851.            else
  3852.           err_exp(sp,as_and_then);
  3853.            end;
  3854.         else
  3855.            if a_e3 then
  3856.           !!infix_and.make(left_part,sp,last_expression);
  3857.           a_r3(infix_and);
  3858.            else
  3859.           err_exp(sp,as_and);
  3860.            end;
  3861.         end;
  3862.      else
  3863.         last_expression := left_part;
  3864.      end;
  3865.       end;
  3866.  
  3867.    a_r4(left_part: like last_expression) is
  3868.      --++ r4 -> "=" e4 r4 |
  3869.      --++       "/=" e4 r4 |
  3870.      --++       "<=" e4 r4 |
  3871.      --++       "<" e4 r4 |
  3872.      --++       ">=" e4 r4 |
  3873.      --++       ">" e4 r4 |
  3874.      --++       ^
  3875.      --++
  3876.       local
  3877.      call_infix: CALL_INFIX;
  3878.      sp: POSITION;
  3879.       do
  3880.      if skip1('=') then
  3881.         sp := pos(start_line,start_column);
  3882.         if a_e4 then
  3883.            !CALL_INFIX_EQ!call_infix.make(left_part,sp,last_expression);
  3884.            a_r4(call_infix);
  3885.         else
  3886.            err_exp(sp,as_eq);
  3887.         end;
  3888.      elseif skip2('/','=') then
  3889.         sp := pos(start_line,start_column);
  3890.         if a_e4 then
  3891.            !CALL_INFIX_NEQ!call_infix.make(left_part,sp,last_expression);
  3892.            a_r4(call_infix);
  3893.         else
  3894.            err_exp(sp,as_neq);
  3895.         end;
  3896.      elseif skip2('<','=') then
  3897.         sp := pos(start_line,start_column);
  3898.         if a_e4 then
  3899.            !CALL_INFIX_LE!call_infix.make(left_part,sp,last_expression);
  3900.            a_r4(call_infix);
  3901.         else
  3902.            err_exp(sp,as_le);
  3903.         end;
  3904.      elseif skip2('>','=') then
  3905.         sp := pos(start_line,start_column);
  3906.         if a_e4 then
  3907.            !CALL_INFIX_GE!call_infix.make(left_part,sp,last_expression);
  3908.            a_r4(call_infix);
  3909.         else
  3910.            err_exp(sp,as_ge);
  3911.         end;
  3912.      elseif skip1('<') then
  3913.         sp := pos(start_line,start_column);
  3914.         if a_e4 then
  3915.            !CALL_INFIX_LT!call_infix.make(left_part,sp,last_expression);
  3916.            a_r4(call_infix);
  3917.         else
  3918.            err_exp(sp,as_lt);
  3919.         end;
  3920.      elseif skip1unless2('>','>') then
  3921.         sp := pos(start_line,start_column);
  3922.         if a_e4 then
  3923.            !CALL_INFIX_GT!call_infix.make(left_part,sp,last_expression);
  3924.            a_r4(call_infix);
  3925.         else
  3926.            err_exp(sp,as_gt);
  3927.         end;
  3928.      else
  3929.         last_expression := left_part;
  3930.      end;
  3931.       end;
  3932.  
  3933.    a_r5(left_part: like last_expression) is
  3934.      --++ r5 -> "+" e5 r5 |
  3935.      --++       "-" e5 r5 |
  3936.      --++       ^
  3937.      --++
  3938.       local
  3939.      infix_plus: CALL_INFIX_PLUS;
  3940.      infix_minus: CALL_INFIX_MINUS;
  3941.      sp: POSITION;
  3942.       do
  3943.      if skip1('+') then
  3944.         sp := pos(start_line,start_column);
  3945.         if a_e5 then
  3946.            !!infix_plus.make(left_part,sp,last_expression);
  3947.            a_r5(infix_plus);
  3948.         else
  3949.            err_exp(sp,as_plus);
  3950.         end;
  3951.      elseif skip1('-') then
  3952.         sp := pos(start_line,start_column);
  3953.         if a_e5 then
  3954.            !!infix_minus.make(left_part,sp,last_expression);
  3955.            a_r5(infix_minus);
  3956.         else
  3957.            err_exp(sp,as_minus);
  3958.         end;
  3959.      else
  3960.         last_expression := left_part;
  3961.      end;
  3962.       end;
  3963.  
  3964.    a_r6(left_part: like last_expression) is
  3965.      --++ r6 -> "*" e6 r6 |
  3966.      --++       "//" e6 r6 |
  3967.      --++       "\\" e6 r6 |
  3968.      --++       "/" e6 r6 |
  3969.      --++       ^
  3970.      --++
  3971.       local
  3972.      infix_times: CALL_INFIX_TIMES;
  3973.      infix_int_div: CALL_INFIX_INT_DIV;
  3974.      infix_int_rem: CALL_INFIX_INT_REM;
  3975.      infix_div: CALL_INFIX_DIV;
  3976.      sp: POSITION;
  3977.       do
  3978.      if skip1('*') then
  3979.         sp := pos(start_line,start_column);
  3980.         if a_e6 then
  3981.            !!infix_times.make(left_part,sp,last_expression);
  3982.            a_r6(infix_times);
  3983.         else
  3984.            err_exp(sp,as_muls);
  3985.         end;
  3986.      elseif skip2('/','/') then
  3987.         sp := pos(start_line,start_column);
  3988.         if a_e6 then
  3989.            !!infix_int_div.make(left_part,sp,last_expression);
  3990.            a_r6(infix_int_div);
  3991.         else
  3992.            err_exp(sp,as_slash_slash);
  3993.         end;
  3994.      elseif skip2('\','\') then
  3995.         sp := pos(start_line,start_column);
  3996.         if a_e6 then
  3997.            !!infix_int_rem.make(left_part,sp,last_expression);
  3998.            a_r6(infix_int_rem);
  3999.         else
  4000.            err_exp(sp,as_backslash_backslash);
  4001.         end;
  4002.      elseif skip1unless2('/','=') then
  4003.         sp := pos(start_line,start_column);
  4004.         if a_e6 then
  4005.            !!infix_div.make(left_part,sp,last_expression);
  4006.            a_r6(infix_div);
  4007.         else
  4008.            err_exp(sp,as_slash);
  4009.         end;
  4010.      else
  4011.         last_expression := left_part;
  4012.      end;
  4013.       end;
  4014.  
  4015.    a_r7(left_part: like last_expression) is
  4016.      --++ r7 -> "^" e7 r7 |
  4017.      --++       ^
  4018.      --++
  4019.       local
  4020.          sp: POSITION;
  4021.       do
  4022.          if skip1('^') then
  4023.             sp := pos(start_line,start_column);
  4024.             if a_e7 then
  4025.                a_r7(last_expression);
  4026.                !CALL_INFIX_POWER!last_expression.make(left_part,sp,last_expression);
  4027.             else
  4028.                err_exp(sp,as_pow);
  4029.             end;
  4030.          else
  4031.             last_expression := left_part;
  4032.          end;
  4033.       end;
  4034.  
  4035.    a_r8(left_part: like last_expression) is
  4036.      --++ r8 -> free_operator e8 r8 |
  4037.      --++       ^
  4038.      --++
  4039.       local
  4040.      infix_name: INFIX_NAME;
  4041.      infix_freeop: CALL_INFIX_FREEOP;
  4042.       do
  4043.      if a_free_operator then
  4044.         infix_name := tmp_name.to_infix_name_use;
  4045.         if a_e8 then
  4046.            !!infix_freeop.make(left_part,infix_name,last_expression);
  4047.            a_r8(infix_freeop);
  4048.         else
  4049.            err_exp(infix_name.start_position,infix_name.to_string);
  4050.         end;
  4051.      else
  4052.         last_expression := left_part;
  4053.      end;
  4054.       end;
  4055.  
  4056.    a_r10(do_instruction: BOOLEAN; t: EXPRESSION; fn: FEATURE_NAME;
  4057.      eal: EFFECTIVE_ARG_LIST) is
  4058.      --++ r10 -> "." after_a_dot |
  4059.      --++        ^
  4060.      --++
  4061.       do
  4062.      if skip1('.') then
  4063.         if t /= Void and then t.is_void then
  4064.            eh.add_position(t.start_position);
  4065.            fatal_error("Void is not a valid target.");
  4066.         end;
  4067.         a_after_a_dot(do_instruction,to_call(t,fn,eal));
  4068.      else
  4069.         if do_instruction then
  4070.            last_instruction := to_proc_call(t,fn,eal);
  4071.            last_expression := Void;
  4072.         else
  4073.            last_expression := to_call(t,fn,eal);
  4074.            last_instruction := Void;
  4075.         end;
  4076.      end;
  4077.       end;
  4078.  
  4079.    a_strip: BOOLEAN is
  4080.      --++ a_strip -> "strip" "(" {identifier "," ...} ")"
  4081.       local
  4082.      sp: POSITION;
  4083.       do
  4084.      if a_keyword(fz_strip) then
  4085.         sp := pos(start_line,start_column);
  4086.         if skip1('(') then
  4087.            ok := a_feature_name_list;
  4088.            !E_STRIP!last_expression.make(sp,last_feature_name_list);
  4089.            if not skip1(')') then
  4090.           fcp("')' expected to end a strip expression.");
  4091.            end;
  4092.            Result := true;
  4093.         else
  4094.            fcp("'(' expected to begin a strip list.");
  4095.         end;
  4096.      end;
  4097.       end;
  4098.  
  4099.    a_tag_mark: BOOLEAN is
  4100.      --++ tag_mark -> identifier ":"
  4101.      --++
  4102.       local
  4103.      l, c: INTEGER;
  4104.       do
  4105.      l := line;
  4106.      c := column;
  4107.      if a_identifier then
  4108.         if skip1(':') then
  4109.            Result := true;
  4110.            last_tag_mark := tmp_name.to_tag_name;
  4111.         else
  4112.            go_back_at(l,c);
  4113.         end;
  4114.      end;
  4115.       end;
  4116.  
  4117.    a_then_part_list(ifthenelse: IFTHENELSE) is
  4118.      --++ then_part_list -> {then_part "elseif"}+
  4119.      --++
  4120.       do
  4121.      from
  4122.         if not a_then_part(ifthenelse) then
  4123.            fcp("In %"if ... then ...%".");
  4124.         end;
  4125.      until
  4126.         not a_keyword(fz_elseif)
  4127.      loop
  4128.         if not a_then_part(ifthenelse) then
  4129.            fcp("In %"elseif ... then ...%".");
  4130.         end;
  4131.      end;
  4132.       end;
  4133.  
  4134.    a_then_part(ifthenelse: IFTHENELSE): BOOLEAN is
  4135.      --++ then_part -> expression "then"
  4136.      --++
  4137.       local
  4138.      expression: EXPRESSION;
  4139.       do
  4140.      if a_expression then
  4141.         Result := true;
  4142.         expression := last_expression.add_comment(get_comments);
  4143.         if not a_keyword(fz_then) then
  4144.            wcp("Added %"then%".");
  4145.         end;
  4146.         ifthenelse.add_if_then(expression,a_compound1);
  4147.      end;
  4148.       end;
  4149.  
  4150.    a_type: BOOLEAN is
  4151.      --++ type -> "like" <anchor> | "expanded" class_type | BIT <constant>
  4152.      --++         type_formal_generic | class_type
  4153.      --++
  4154.       local
  4155.      sp: POSITION;
  4156.      argument_name2: ARGUMENT_NAME2;
  4157.       do
  4158.      Result := true;
  4159.      if a_keyword(fz_like) then
  4160.         sp := pos(start_line,start_column);
  4161.         if a_infix then
  4162.            !TYPE_LIKE_FEATURE!last_type.make(sp,last_infix);
  4163.         elseif a_prefix then
  4164.            !TYPE_LIKE_FEATURE!last_type.make(sp,last_prefix);
  4165.         elseif a_identifier then
  4166.            if a_current then
  4167.           !TYPE_LIKE_CURRENT!last_type.make(sp);
  4168.            elseif a_argument then
  4169.           argument_name2 ?= last_expression;
  4170.           !TYPE_LIKE_ARGUMENT!last_type.make(sp,argument_name2);
  4171.            else
  4172.           !TYPE_LIKE_FEATURE!last_type.make(sp,
  4173.                             tmp_name.to_simple_feature_name);
  4174.            end;
  4175.         else
  4176.            fcp("Anchor expected. An anchor could be `Current', %
  4177.            %a feature name or an argument name.");
  4178.         end;
  4179.      elseif a_keyword(fz_expanded) then
  4180.         sp := pos(start_line,start_column);
  4181.         if a_class_type then
  4182.            !TYPE_EXPANDED!last_type.make(sp,last_class_type);
  4183.         else
  4184.            fcp("Must find a class type after %"expanded%".");
  4185.         end;
  4186.      elseif a_keyword(as_bit) then
  4187.         sp := pos(start_line,start_column);
  4188.         if a_integer then
  4189.            !TYPE_BIT_1!last_type.make(sp,last_integer_constant);
  4190.         elseif a_identifier then
  4191.            !TYPE_BIT_2!last_type.make(sp,tmp_name.to_simple_feature_name);
  4192.         else
  4193.            fcp("Expected constant for BIT_N type declaration.");
  4194.         end;
  4195.      elseif a_type_formal_generic then
  4196.         last_type := last_type_formal_generic;
  4197.      elseif a_class_type then
  4198.         last_type := last_class_type;
  4199.      else
  4200.         Result := false;
  4201.      end;
  4202.       end;
  4203.  
  4204.    a_unary: BOOLEAN is
  4205.      --++ unary -> "not" | "+" | "-"
  4206.      --++
  4207.       do
  4208.      if a_keyword(as_not) then
  4209.         !!last_prefix.make(as_not,pos(start_line,start_column));
  4210.         Result := true;
  4211.      elseif skip1('+') then
  4212.         !!last_prefix.make(as_plus,pos(start_line,start_column));
  4213.         Result := true;
  4214.      elseif skip1('-') then
  4215.         !!last_prefix.make(as_minus,pos(start_line,start_column));
  4216.         Result := true;
  4217.      end;
  4218.       end;
  4219.  
  4220.    a_when_part(i: E_INSPECT): BOOLEAN is
  4221.      --++ when_part -> "when" {when_part_item "," ...} then compound
  4222.      --++
  4223.      --++ when_part_item -> constant ".." constant |
  4224.      --++                   constant
  4225.      --++
  4226.      --++ constant -> character_constant | integer_constant | identifier
  4227.      --++
  4228.       local
  4229.      state: INTEGER;
  4230.      -- state 0 : sepator read, waiting a constant or "then".
  4231.      -- state 1 : first constant read.
  4232.      -- state 2 : ".." read.
  4233.      -- state 3 : slice read.
  4234.      -- state 4 : end.
  4235.      e_when: E_WHEN;
  4236.      constant: EXPRESSION;
  4237.       do
  4238.      if a_keyword(fz_when) then
  4239.         from
  4240.            Result := true;
  4241.            !!e_when.make(pos(start_line,start_column),get_comments);
  4242.         until
  4243.            state > 3
  4244.         loop
  4245.            inspect
  4246.           state
  4247.            when 0 then
  4248.           if a_constant then
  4249.              constant := last_expression;
  4250.              state := 1;
  4251.           elseif a_keyword(fz_then) then
  4252.              if constant /= Void then
  4253.             e_when.add_value(constant);
  4254.              end;
  4255.              e_when.set_compound(a_compound1);
  4256.              i.add_when(e_when);
  4257.              state := 4;
  4258.           elseif cc = ',' then
  4259.              wcp(em7);
  4260.              ok := skip1(',');
  4261.           else
  4262.              fcp(em4);
  4263.              state := 4;
  4264.           end;
  4265.            when 1 then
  4266.           if a_keyword(fz_then) then
  4267.              if constant /= Void then
  4268.             e_when.add_value(constant);
  4269.              end;
  4270.              e_when.set_compound(a_compound1);
  4271.              i.add_when(e_when);
  4272.              state := 4;
  4273.           elseif skip2('.','.') then
  4274.              state := 2;
  4275.           elseif skip1(',') then
  4276.              e_when.add_value(constant);
  4277.              constant := Void;
  4278.              state := 0;
  4279.           else
  4280.              fcp(em4);
  4281.              state := 4;
  4282.           end;
  4283.            when 2 then
  4284.           if a_constant then
  4285.              e_when.add_slice(constant,last_expression);
  4286.              constant := Void;
  4287.              state := 3;
  4288.           else
  4289.              fcp(em4);
  4290.              state := 4;
  4291.           end;
  4292.            else -- state = 3
  4293.           if skip1(',') then
  4294.              state := 0;
  4295.           elseif a_keyword(fz_then) then
  4296.              e_when.set_compound(a_compound1);
  4297.              i.add_when(e_when);
  4298.              state := 4;
  4299.           elseif a_constant then
  4300.              constant := last_expression;
  4301.              warning(tmp_name.start_position,em5);
  4302.              state := 1;
  4303.           else
  4304.              fcp(em4);
  4305.              state := 4;
  4306.           end;
  4307.            end;
  4308.         end;
  4309.      end;
  4310.       end;
  4311.  
  4312.    mandatory_writable: EXPRESSION is
  4313.      -- Skip and return the writable which is mandatory here.
  4314.       do
  4315.      if a_identifier then
  4316.         if a_current then
  4317.            eh.add_position(last_expression.start_position);
  4318.            eh.append("Current is not a writable variable.");
  4319.            eh.print_as_fatal_error;
  4320.         elseif a_argument then
  4321.            eh.add_position(last_expression.start_position);
  4322.            eh.append(em21);
  4323.            eh.print_as_fatal_error;
  4324.         elseif a_result or else a_local_variable then
  4325.            Result := last_expression;
  4326.         else
  4327.            Result := tmp_name.to_simple_feature_name;
  4328.         end;
  4329.      else
  4330.         fcp(em22);
  4331.      end;
  4332.       ensure
  4333.      Result /= Void
  4334.       end;
  4335.    
  4336.    to_call(t: EXPRESSION; fn: FEATURE_NAME;
  4337.        eal: EFFECTIVE_ARG_LIST): EXPRESSION is
  4338.       require
  4339.      t /= Void;
  4340.       do
  4341.      if fn = Void then
  4342.         check
  4343.            eal = Void;
  4344.         end;
  4345.         Result := t;
  4346.      elseif eal = Void then
  4347.         !CALL_0_C!Result.make(t,fn);
  4348.      elseif eal.count = 1 then
  4349.         !CALL_1_C!Result.make(t,fn,eal);
  4350.      else
  4351.         !CALL_N!Result.make(t,fn,eal);
  4352.      end;
  4353.       end;
  4354.  
  4355.    to_proc_call(t: EXPRESSION; fn: FEATURE_NAME;
  4356.         eal: EFFECTIVE_ARG_LIST): PROC_CALL is
  4357.       do
  4358.      if fn = Void then
  4359.         fcp("An expression has a result value. %
  4360.         %This is not an instruction.");
  4361.      elseif eal = Void then
  4362.         !PROC_CALL_0!Result.make(t,fn);
  4363.      elseif eal.count = 1 then
  4364.         !PROC_CALL_1!Result.make(t,fn,eal);
  4365.      else
  4366.         !PROC_CALL_N!Result.make(t,fn,eal);
  4367.      end;
  4368.       end;
  4369.  
  4370.    wcpefnc(old_name, new_name: STRING) is
  4371.       do
  4372.      eh.append("For readability, the keyword %"");
  4373.      eh.append(old_name);
  4374.      eh.append("%" is now %"");
  4375.      eh.append(new_name);
  4376.      wcp("%". You should update your Eiffel code now.");
  4377.       end;
  4378.  
  4379.    forbidden_class: ARRAY[STRING] is
  4380.       once
  4381.      Result := <<as_none>>;
  4382.       end;
  4383.  
  4384.    lcs: STRING is
  4385.      -- Last Comment String.
  4386.       once
  4387.      !!Result.make(80);
  4388.       end;
  4389.  
  4390.    tmp_string: STRING is
  4391.       once
  4392.      !!Result.make(80);
  4393.       end;
  4394.  
  4395.    a_identifier1: BOOLEAN is
  4396.      -- Case Insensitive (option -case_insensitive).
  4397.       require
  4398.      case_insensitive
  4399.       local
  4400.      state, c: INTEGER;
  4401.      -- state 0 : first letter read.
  4402.      -- state 1 : end.
  4403.       do
  4404.      if cc.is_letter then
  4405.         from
  4406.            c := column;
  4407.            tmp_name.reset(pos(line,c));
  4408.            tmp_name.extend(cc.to_lower);
  4409.         until
  4410.            state > 0
  4411.         loop
  4412.            next_char;
  4413.            inspect
  4414.           cc
  4415.            when 'a'..'z','0'..'9','_' then
  4416.           tmp_name.extend(cc);
  4417.            when 'A'..'Z' then
  4418.           tmp_name.extend(cc.to_lower);
  4419.            else
  4420.           state := 1;
  4421.            end;
  4422.         end;
  4423.         if tmp_name.isa_keyword then
  4424.            cc := tmp_name.buffer.first;
  4425.            column := c;
  4426.         else
  4427.            Result := true;
  4428.            skip_comments;
  4429.         end;
  4430.      end;
  4431.       end;
  4432.  
  4433.    a_identifier2: BOOLEAN is
  4434.      -- Case Sensitivity for identifiers (default).
  4435.       require
  4436.      not case_insensitive
  4437.       local
  4438.      state, c: INTEGER;
  4439.      do_warning: BOOLEAN;
  4440.      -- state 0 : first letter read.
  4441.      -- state 1 : end.
  4442.       do
  4443.      if cc.is_letter then
  4444.         from
  4445.            c := column;
  4446.            tmp_name.reset(pos(line,c));
  4447.            tmp_name.extend(cc);
  4448.         until
  4449.            state > 0
  4450.         loop
  4451.            next_char;
  4452.            inspect
  4453.           cc
  4454.            when 'a'..'z','0'..'9','_' then
  4455.           tmp_name.extend(cc);
  4456.            when 'A'..'Z' then
  4457.           do_warning := true;
  4458.           tmp_name.extend(cc);
  4459.            else
  4460.           state := 1;
  4461.            end;
  4462.         end;
  4463.         if tmp_name.isa_keyword then
  4464.            cc := tmp_name.buffer.first;
  4465.            column := c;
  4466.         else
  4467.            Result := true;
  4468.            skip_comments;
  4469.            if no_style_warning then
  4470.            elseif do_warning then
  4471.           warning(tmp_name.start_position,
  4472.               "Identifier should use only lowercase letters.");
  4473.            end;
  4474.         end;
  4475.      end;
  4476.       end;
  4477.  
  4478.    line, column: INTEGER;
  4479.      -- Current `line' number and current `column' number.
  4480.  
  4481.    current_line: STRING;
  4482.      -- Current line string of `text'.
  4483.  
  4484.    cc: CHARACTER;
  4485.      -- Current character in the `current_line'.
  4486.  
  4487.    show_nb(nb: INTEGER; tail: STRING) is
  4488.       do
  4489.      if nb > 0 then
  4490.         echo.w_put_string(fz_error_stars);
  4491.         echo.w_put_integer(nb);
  4492.         echo.w_put_string(tail);
  4493.      end;
  4494.       end;
  4495.  
  4496.    tmp_feature: TMP_FEATURE;
  4497.  
  4498.    drop_comments: BOOLEAN;
  4499.      -- When objects COMMENT are not necessary.
  4500.  
  4501.    current_id: INTEGER;
  4502.      -- This is the `id' of the `last_base_class' or the `id' of 
  4503.      -- the cecil file path.
  4504.  
  4505.    pos(l, c: INTEGER): POSITION is
  4506.       require
  4507.      l >= 1;
  4508.      c >= 1
  4509.       do
  4510.      Result.set(l,c,current_id,last_base_class);
  4511.       end;
  4512.  
  4513.    to_frozen_feature_name is
  4514.       do
  4515.      !FROZEN_FEATURE_NAME!last_feature_name.make(last_feature_name);
  4516.       end;
  4517.  
  4518.    last_result: ABSTRACT_RESULT is
  4519.       local
  4520.      sp: POSITION;
  4521.       do
  4522.      sp := tmp_name.start_position;
  4523.      if inside_function then
  4524.         if inside_once_function then
  4525.            !ONCE_RESULT!Result.make(sp);
  4526.         else
  4527.            !ORDINARY_RESULT!Result.make(sp);
  4528.         end;
  4529.      else
  4530.         eh.add_position(sp);
  4531.         fatal_error("`Result' must only be used inside a function.");
  4532.      end;
  4533.       ensure
  4534.      Result /= Void
  4535.       end;
  4536.  
  4537.    faof: FIXED_ARRAY[E_FEATURE] is
  4538.       once
  4539.      !!Result.with_capacity(256);
  4540.       end;
  4541.  
  4542.    err_exp(sp: POSITION; operator: STRING) is
  4543.      -- When an error occurs in the right hand side of `operator'.
  4544.       local
  4545.      msg: STRING;
  4546.       do
  4547.      !!msg.make(0);
  4548.      msg.append("Right hand side expression of %"");
  4549.      msg.append(operator);
  4550.      msg.append("%" expected.");
  4551.      eh.add_position(sp);
  4552.      fatal_error(msg);
  4553.       end;
  4554.  
  4555.    fcp(msg: STRING) is
  4556.      -- Fatal error at current position.
  4557.       do
  4558.      eh.add_position(current_position);
  4559.      fatal_error(msg);
  4560.       end;
  4561.  
  4562.    wcp(msg: STRING) is
  4563.      -- Warning at current position.
  4564.       do
  4565.      warning(current_position,msg);
  4566.       end;
  4567.  
  4568.    current_position: POSITION is
  4569.       do
  4570.      Result := pos(line,column);
  4571.       end;
  4572.  
  4573.    em1 : STRING is "Underscore in fractionnal part must group 3 digits.";
  4574.    em2 : STRING is "Feature name expected.";
  4575.    em3 : STRING is "Index value expected (%"indexing ...%").";
  4576.    em4 : STRING is "Error in inspect.";
  4577.    em5 : STRING is "Added %",%".";
  4578.    em6 : STRING is "Added %";%".";
  4579.    em7 : STRING is "Unexpected comma (deleted)."
  4580.    em8 : STRING is "Unexpected new line in manifest string.";
  4581.    em9 : STRING is "Underscore in number must group 3 digits.";
  4582.    em10: STRING is "Bad character constant.";
  4583.    em11: STRING is "Bad clients list.";
  4584.    em12: STRING is "Deleted extra coma.";
  4585.    em13: STRING is "Deleted extra separator.";
  4586.    em14: STRING is "Class name should use only uppercase letters.";
  4587.    em15: STRING is "Name of the current class expected.";
  4588.    em16: STRING is "Type mark expected.";
  4589.    em17: STRING is "Unexpected character.";
  4590.    em18: STRING is "Bad external clause ('%"' expected).";
  4591.    em19: STRING is "Bad alias clause ('%"' expected).";
  4592.    em20: STRING is "Explicit creation/create type mark must not be anchored.";
  4593.    em21: STRING is "A formal argument is not a writable variable.";
  4594.    em22: STRING is "Bad creation/create (writable expected).";
  4595.    em23: STRING is "Bad creation/create (procedure name expected).";
  4596.  
  4597.    singleton_memory: EIFFEL_PARSER is
  4598.       once
  4599.      Result := Current;
  4600.       end;
  4601.  
  4602. invariant
  4603.  
  4604.    is_real_singleton: Current = singleton_memory
  4605.  
  4606. end -- EIFFEL_PARSER
  4607.  
  4608.